/ / Wie identifiziere ich die Spalte (n), die für "String oder Binärdaten werden abgeschnitten" verantwortlich sind. - SQL, SQL-Server, SQL-Server-2008

Wie identifiziere ich die Spalte (n), die für "Zeichenfolge oder Binärdaten werden abgeschnitten" verantwortlich sind. - SQL, SQL-Server, SQL-Server-2008

Ich habe eine INSERT-Anweisung, die so aussieht:

INSERT INTO CLIENT_TABLE
SELECT NAME, SURNAME, AGE FROM CONTACT_TABLE

Mein Beispiel oben ist ein grundlegendes, aber gibt es eine Möglichkeit, eine SELECT-Anweisung zu übergeben und dann die zurückgegebenen Spaltenwerte mit den tatsächlichen Feldgrößen zu vergleichen?

Es ist nicht praktikabel, LEN gegen jede Spalte zu prüfen. Ich suche etwas, das automatisiert ist.

Antworten:

2 für die Antwort № 1

Mein Debugging in dieser Art von Problem ist ..

Ich entferne Spalten in der SELECT Wenn nacheinander kein Fehler zurückgegeben wurde, wissen Sie, welche Spalte die Ursache für das Abschneideproblem ist. Hier finden Sie jedoch einige Tipps zum Debuggen.

  • Option 1: Beginnen Sie zuerst mit den Spalten, die mehr Zeichen enthalten VARCHARZum Beispiel in Ihrem Fall denke ich die Spalte NAME, SURNAME sind die, die da einen fehler verursachen AGE Die Spalte enthält aufgrund ihrer Ganzzahl nicht viele Zeichen. Sie sollten so etwas debuggen.

  • Option 2: Sie können die Spalte in Ihrer endgültigen Ausgabe untersuchen. Das endgültige SELECT Wenn alle Spalten und ihre Werte zurückgegeben werden, können Sie überprüfen, ob die Werte mit den auf der Benutzeroberfläche usw. eingegebenen Werten übereinstimmen.

    Ex. Siehe die Erwartete vs. tatsächliche Leistung Ergebnis auf dem Bild unten

    Erwartet:

    Bildbeschreibung hier eingeben

    Tatsächliche Ausgabe:

    Bildbeschreibung hier eingeben

    Mein Beispiel in Option 2 zeigt, dass die abgeschnittene Zeichenfolge die ist SURNAME Wie du siehst..

    HINWEIS: Sie können Option 2 nur verwenden, wenn die Abfrage keinen Ausführungsfehler zurückgegeben hat. Dies bedeutet, dass die abgeschnittene Zeichenfolge keinen Fehler zurückgegeben hat ABER hat eine unerwartete geteilte Zeichenfolge erstellt, die wir nicht wollen.

    OB Die Abfrage gibt einen Fehler zurück. Ihre beste Wahl ist Option 1, die aber mehr Zeit in Anspruch nimmt es ist es wertDies ist der beste Weg, um sicherzustellen, dass Sie die genaue Spalte gefunden haben, die das Kürzungsproblem verursacht

Dann, wenn Sie bereits die Spalten gefunden haben, die verursachtDas Problem ist, dass Sie jetzt die Größe der Spalte anpassen können oder eine andere Möglichkeit darin besteht, die Eingabe des Benutzers zu begrenzen. Sie können den Benutzern eine Validierung geben, um Kürzungsprobleme zu vermeiden, aber es liegt ganz bei Ihnen, wie Sie das Programm möchten funktioniert je nach Ihren Anforderungen.

Meine Antworten / Vorschläge basieren auf meinen Erfahrungen in solchen Situationen.

Hoffe, diese Antwort wird Ihnen helfen. :) :)


1 für die Antwort № 2

Überprüfen Sie die maximale Länge für jedes Feld. Auf diese Weise können Sie die Felder identifizieren, die über dem in Ihrer Tabelle angegebenen Zeichenlimit liegen, z CLIENT_TABLE.

    SELECT Max(Len(NAME)) MaxNamePossible
, Max(Len(SURNAME)) MaxSurNamePossible
, Max(Len(AGE)) MaxAgePossible
FROM CONTACT_TABLE

Vergleichen Sie das Ergebnis mit Client_Table Design Wie wenn in Client_Table "Name" ist vom Typ Varchar(50) und die oben beschriebene Validierungsabfrage gibt mehr als 50 Zeichen zurück, als das Feld "Name" einen Überlauf verursacht.


1 für die Antwort № 3

Es gibt eine großartige Antwort von Aaron Bertrand auf die Frage: Ruft die Spaltendefinition für die Ergebnismenge der gespeicherten Prozedur ab

Wenn Sie SQL Server 2012+ verwendet haben, können Sie verwenden sys.dm_exec_describe_first_result_set. Hier ist ein schöner Artikel mit Beispielen. Aber auch in SQL Server 2008 ist es möglich, die Spaltentypen der Abfrage abzurufen. Aarons Antwort erklärt es im Detail.

In Ihrem Fall ist es sogar einfacher, da Sie eine haben SELECT Anweisung, dass Sie kopieren und einfügen können, nicht etwas, das in einer gespeicherten Prozedur versteckt ist. Ich gehe davon aus, dass Ihr SELECT ist eine komplexe Abfrage, die Spalten aus vielen Tabellen zurückgibt. Wenn es nur ein Tisch wäre, könnten Sie ihn verwenden sys.columns mit dieser Tabelle direkt.

Erstellen Sie also eine leere #tmp1 Tabelle basierend auf Ihrem Komplex SELECT:

SELECT TOP(0)
NAME, SURNAME, AGE
INTO #tmp1
FROM CONTACT_TABLE;

Erstellen Sie eine Sekunde #tmp2 Tabelle basierend auf dem Ziel Ihres Komplexes SELECT:

SELECT TOP(0)
NAME, SURNAME, AGE
INTO #tmp2
FROM CLIENT_TABLE;

Beachten Sie, dass wir keine Zeilen benötigen, sondern nur Spalten für Metadaten TOP(0) ist praktisch. Einmal die #tmp Tabellen existieren, wir können ihre Metadaten mit abfragen sys.columns und vergleiche es:

WITH
CTE1
AS
(
SELECT
c.name AS ColumnName
,t.name AS TypeName
,c.max_length
,c.[precision]
,c.scale
FROM
tempdb.sys.columns AS c
INNER JOIN tempdb.sys.types AS t ON
c.system_type_id = t.system_type_id
AND c.user_type_id = t.user_type_id
WHERE
c.[object_id] = OBJECT_ID("tempdb.dbo.#tmp1")
)
,CTE2
AS
(
SELECT
c.name AS ColumnName
,t.name AS TypeName
,c.max_length
,c.[precision]
,c.scale
FROM
tempdb.sys.columns AS c
INNER JOIN tempdb.sys.types AS t ON
c.system_type_id = t.system_type_id
AND c.user_type_id = t.user_type_id
WHERE
c.[object_id] = OBJECT_ID("tempdb.dbo.#tmp2")
)
SELECT *
FROM
CTE1
FULL JOIN CTE2 ON CTE1.ColumnName = CTE2.ColumnName
WHERE
CTE1.TypeName <> CTE2.TypeName
OR CTE1.max_length <> CTE2.max_length
OR CTE1.[precision] <> CTE2.[precision]
OR CTE1.scale <> CTE2.scale
;

Eine andere Möglichkeit zu vergleichen:

WITH

... as above ...

SELECT * FROM CTE1

EXCEPT

SELECT * FROM CTE2
;

Endlich

DROP TABLE #tmp1;
DROP TABLE #tmp2;

Sie können den Vergleich an Ihre Bedürfnisse anpassen.


0 für die Antwort № 4

Eine manuelle Lösung ist sehr schnell, wenn Sie SQL Server Manager Studio (SSMS) verwenden. Erfassen Sie zuerst die Tabellenstruktur Ihrer SELECT-Anweisung in einer Arbeitstabelle:

SELECT COL1, COL2, ... COL99 INTO dbo.zz_CONTACT_TABLE
FROM CONTACT_TABLE WHERE 1=0;

Klicken Sie dann in SSMS mit der rechten Maustaste auf Ihr OriginalZieltabelle (CLIENT_TABLE) und Skript zum Erstellen in ein neues SSMS-Fenster. Klicken Sie dann mit der rechten Maustaste auf Ihre Arbeitstabelle (zz_CONTACT_TABLE) und schreiben Sie die Erstellung dieser Tabelle in ein zweites SSMS-Fenster. Ordnen Sie beide Fenster nebeneinander an und vergleichen Sie die Spalten von zz_CONTACT_TABLE mit CLIENT_TABLE. Unterschiede in der Länge und Spalten außerhalb der Reihenfolge werden sofort sichtbar, selbst wenn Hunderte von Ausgabespalten vorhanden sind.

Lassen Sie zum Schluss Ihren Arbeitstisch fallen:

DROP TABLE dbo.zz_CONTACT_TABLE;

In Bezug auf eine automatisierte Lösung ist es schwierigum zu sehen, wie das funktionieren könnte. Grundsätzlich vergleichen Sie eine Zieltabelle (oder eine Teilmenge von Spalten in einer Zieltabelle) mit der Ausgabe einer SELECT-Anweisung. Ich nehme an, Sie könnten eine gespeicherte Prozedur schreiben, die zwei varchar-Parameter akzeptiert: den Namen der Zieltabelle und die SELECT-Anweisung, die sie füllen würde. Dies würde jedoch nicht den Fall behandeln, in dem nur einige Spalten des Ziels ausgefüllt sind, und es wäre mehr Arbeit als die oben beschriebene manuelle Lösung.


0 für die Antwort № 5

Hier ist ein Code zum Vergleichen von zwei ZeilenSQL-Anweisungen zum Vergleichen der Spalten. Als Parameter werden zwei Zeilensätze verwendet, die mit Servername, Datenbankname und T-SQL-Abfrage angegeben sind. Es kann Daten in verschiedenen Datenbanken und sogar auf verschiedenen SQL Servern vergleichen.

--setup parameters
declare @Server1 as varchar(128)
declare @Database1 as varchar(128)
declare @Query1 as varchar(max)
declare @Server2 as varchar(128)
declare @Database2 as varchar(128)
declare @Query2 as varchar(max)
set @Server1 = "(local)"
set @Database1 = "MyDatabase"
set @Query1 = "select * from MyTable" --use a select
set @Server2 = "(local)"
set @Database2 = "MyDatabase2"
set @Query2 = "exec MyTestProcedure...." --or use a procedure

--calculate statement column differences
declare @SQLStatement1 as varchar(max)
declare @SQLStatement2 as varchar(max)

set @Server1 = replace(@Server1,"""","""""")
set @Database1 = replace(@Database1,"""","""""")
set @Query1 = replace(@Query1,"""","""""")
set @Server2 = replace(@Server2,"""","""""")
set @Database2 = replace(@Database2,"""","""""")
set @Query2 = replace(@Query2,"""","""""")

CREATE TABLE #Qry1Columns(
[colorder] [smallint] NULL,
[ColumnName] [sysname] COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[TypeName] [sysname] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[prec] [smallint] NULL,
[scale] [int] NULL,
[isnullable] [int] NULL,
[collation] [sysname] COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]

CREATE TABLE #Qry2Columns(
[colorder] [smallint] NULL,
[ColumnName] [sysname] COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[TypeName] [sysname] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[prec] [smallint] NULL,
[scale] [int] NULL,
[isnullable] [int] NULL,
[collation] [sysname] COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]

set @SQLStatement1 =
"SELECT *
INTO #Qry1
FROM OPENROWSET(""SQLNCLI"",
""server=" + @Server1 + ";database=" + @Database1 + ";trusted_connection=yes"",
""select top 0 * from (" + @Query1 + ") qry"")

select colorder, syscolumns.name ColumnName, systypes.name TypeName, syscolumns.prec, syscolumns.scale, syscolumns.isnullable, syscolumns.collation
from tempdb.dbo.syscolumns
join tempdb.dbo.systypes
on syscolumns.xtype = systypes.xtype
where id = OBJECT_ID(""tempdb.dbo.#Qry1"")
order by 1"

insert into #Qry1Columns
exec(@SQLStatement1)


set @SQLStatement2 =
"SELECT *
INTO #Qry1
FROM OPENROWSET(""SQLNCLI"",
""server=" + @Server2 + ";database=" + @Database2 + ";trusted_connection=yes"",
""select top 0 * from (" + @Query2 + ") qry"")

select colorder, syscolumns.name ColumnName, systypes.name TypeName, syscolumns.prec, syscolumns.scale, syscolumns.isnullable, syscolumns.collation
from tempdb.dbo.syscolumns
join tempdb.dbo.systypes
on syscolumns.xtype = systypes.xtype
where id = OBJECT_ID(""tempdb.dbo.#Qry1"")
order by 1"

insert into #Qry2Columns
exec(@SQLStatement2)

select ISNULL( #Qry1Columns.colorder, #Qry2Columns.colorder) ColumnNumber,
#Qry1Columns.ColumnName ColumnName1,
#Qry1Columns.TypeName TypeName1,
#Qry1Columns.prec prec1,
#Qry1Columns.scale scale1,
#Qry1Columns.isnullable isnullable1,
#Qry1Columns.collation collation1,
#Qry2Columns.ColumnName ColumnName2,
#Qry2Columns.TypeName TypeName2,
#Qry2Columns.prec prec2,
#Qry2Columns.scale scale2,
#Qry1Columns.isnullable isnullable2,
#Qry2Columns.collation collation2
from #Qry1Columns
join #Qry2Columns
on #Qry1Columns.colorder=#Qry2Columns.colorder

Sie können die Anweisung finally select an anpassenMarkieren Sie alle gewünschten Unterschiede. Sie können dies auch in eine Prozedur einwickeln und eine nette kleine Benutzeroberfläche dafür erstellen, wenn Sie möchten, so dass es buchstäblich ein Ausschneiden und Einfügen ist, um schnelle Ergebnisse zu erzielen.