| 

.NET C# Java Javascript Exception

1
Hallo,

wir haben eine Abfrage im Einsatz, die in speziellen Fällen einen Fehler 8152 "Zeichenfolgen- oder Binärdaten würden abgeschnitten" liefert.
Wir können das Problem mit folgendem Query nachstellen:

CREATE TABLE SourceValues (
SourceId INT IDENTITY (1,1),
SourceValue VARCHAR(3)
)
GO
INSERT INTO SourceValues (SourceValue) VALUES ('aaa')
INSERT INTO SourceValues (SourceValue) VALUES ('aab')
INSERT INTO SourceValues (SourceValue) VALUES ('aa')
INSERT INTO SourceValues (SourceValue) VALUES ('ab')
INSERT INTO SourceValues (SourceValue) VALUES ('a')
INSERT INTO SourceValues (SourceValue) VALUES ('b')
GO

PRINT 'NOT WORKING #1'
CREATE TABLE TargetValues (TargetValue VARCHAR(2))
INSERT INTO TargetValues (TargetValue)
SELECT s1.SourceValue FROM SourceValues s1, SourceValues s2 WHERE s1.SourceId=s2.SourceId+1 AND s1.SourceValue!='aab'
DROP TABLE TargetValues
GO

PRINT 'NOT WORKING #2'
CREATE TABLE TargetValues (TargetValue VARCHAR(2))
INSERT INTO TargetValues (TargetValue)
SELECT s1.SourceValue FROM SourceValues s1, SourceValues s2 WHERE s1.SourceId=s2.SourceId+1 AND s1.SourceValue!='aab'
ORDER BY s1.SourceValue
DROP TABLE TargetValues
GO

PRINT 'WORKING #1'
CREATE TABLE TargetValues (TargetValue VARCHAR(2))
INSERT INTO TargetValues (TargetValue)
SELECT s1.SourceValue FROM SourceValues s1, SourceValues s2 WHERE s1.SourceId=s2.SourceId+1 AND s1.SourceValue!='aab'
ORDER BY s2.SourceValue -- <-- using s2 instead of s1 for order
DROP TABLE TargetValues
GO

PRINT 'WORKING #2'
CREATE TABLE TargetValues (TargetId INT IDENTITY (1,1),TargetValue VARCHAR(2)) -- <-- using identity column
INSERT INTO TargetValues (TargetValue)
SELECT s1.SourceValue FROM SourceValues s1, SourceValues s2 WHERE s1.SourceId=s2.SourceId+1 AND s1.SourceValue!='aab'
DROP TABLE TargetValues
GO

DROP TABLE SourceValues


Ausgangspunkt unseres Problems ist das Query bei 'NOT WORKING #1'.
Die anderen drei sind von uns bis jetzt erforschte Lösungsversuche (Workarounds).
Kann mir jemand vielleicht erklären, wieso es beim Ausführen der ersten beiden Varianten zu einer Fehlermeldung kommt und bei den letzten beiden Varianten nicht?
27.06.2011
woni 170 1 4
2 Antworten
4
Schau Dir doch mal die Datentypen an... In Deiner Tabelle "TargetValues()" hast Du die Spalte als VARCHAR(2), es passen also maximal 2 Zeichen rein.

In der Ausgangstabelle stehen aber in einer Zeile 3 Zeichen drin! Die passen einfach nicht in die Spalte mit VARCHAR(2) rein, würden also "abgeschnitten" (wenn diese im SELECT mit rauskommen würden)!

Die SQL Engine ist hier einfach nicht "intelligent" genug, um zu erkennen, dass diese Zeile gar nicht im Ergebnis mit enthalten ist. Er schaut einfach nur auf den Datentyp, und theoretisch könnte ein VARCHAR(3) daherkommen, der nicht in die Zieltabelle reinpasst.

BTW: Bei mir (SQL Server 2008 R2) kommt die Fehlermeldung bei allen 4 Abfragen, und nicht nur bei den ersten beiden! Dein WORKING#1 und WORKING#2 laufen bei mir auch nicht!

Eine mögliche Variante:

PRINT 'NOW WORKING #1'
CREATE TABLE TargetValues (TargetValue VARCHAR(2))
INSERT INTO TargetValues (TargetValue)
SELECT CONVERT(VARCHAR(2),s1.SourceValue) FROM SourceValues s1, SourceValues s2 WHERE s1.SourceId=s2.SourceId+1 AND s1.SourceValue!='aab'
DROP TABLE TargetValues
GO
27.06.2011
commänder 420 1 7
Wir konnten das bis jetzt auf einem SQL Server 2005, SQL Server 2008 und SQL Server 2008 R2 (SP1) nachstellen. Also ich glaub auch nicht, dass dies etwas mit der Version des Servers zu tun hat.
woni 27.06.2011
Zu deinem Statement:
Ich glaub die SQL Engine versteht das schon, wenn man den Test ohne die dreistelligen Einträge ausführt, dann funktionieren alle Querys.
woni 27.06.2011
Bilde ich mir das ein, oder filtert er nicht ausschließlich nach "AND s1.SourceValue!='aab'". In der Quelltabelle gibt es aab UND aaa. Also noch ein zweiter Datensatz mit 3 Zeichen.
Jens Duczmal 27.06.2011
1
@Jens: 'aaa' fliegt raus, weil die Zeile die ID 1 hat und es kein s2 gibt mit ID 0, d.h. die Bedingung "s1.SourceId=s2.SourceId+1" ist für kein s2 aus SourceValues erfüllt.
Matthias Hlawatsch 27.06.2011
3
ich kanns dir nicht erklären, will aber schon die provokante frage stellen: wenn schon varchar, warum nicht varchar(200) (oder was immer für ein wert sinnvoll erscheint, varchars brauchen eh nur platz für das, was drinnsteht + ganz wenig verwaltungsoverhead)
27.06.2011
nabuchodonossor 1,3k 5
2
@alle besserwisser: ich weiss, ich hätte es als kommentar reinschreiben können
nabuchodonossor 27.06.2011
Danke, auf das wirds später herauskommen, aber mir geht es eher warum zwei Querys funktionieren und zwei nicht. Oder wie bei commänder alle 4 nicht.
woni 27.06.2011
1
ich versteh deine neugierte schon, sowas kann einen ganz schön quälen. gerade aber in dem offensichtlichen fall ist die zieltabelle mit dem varchar(2) nicht geeignet. wenn es manchmal geht und manchmal nicht, fiele mir nur mehr ein, sich den execution plan der statements anzusehen, um den unterschied festzustellen.
nabuchodonossor 27.06.2011
1
neugierde statt neugierte ... eh klar.
nabuchodonossor 27.06.2011
Die Neugierde besteht darin, dass der Kunde gerne wissen möchte warum sein Produkt, für das er bezahlt, nicht funktioniert hatte.
Der Execution-Plan ist eine gute Idee, kann ich mir mal anschauen.
woni 27.06.2011

Stelle deine Sql-Frage jetzt!