Weird SQL server Lazy Laden von Tabellenvariablen?

Ich stieß auf einen irreführenden Fehler in SQL server 2008 und ich frage mich, ob jemand erklären kann, was mit mir passiert?

Ich habe eine gespeicherte Prozedur so etwas wie dieses:

declare @cross_reference table ( context varchar(20) not null , value1 varchar(10) not null , value2 varchar(10) not null ) insert into @cross_reference values ('map', 'from_value', 'to_value') insert into @cross_reference values ('map', 'from_value', 'to_value') insert into @cross_reference values ('map', 'from_value_xxxxx', 'to_value_xxxxxxx') select t1.field1 , t1.field2 , xref.value2 from table_1 t1 inner join table_2 t2 on t2.id = t1.id left join @cross_reference xref on xref.context = 'map' and xref.value1 = t2.map_id 

Der eigentliche gespeicherte Proc ist komplexer, aber das ist der core.

Beim Ausführen der SP bekomme ich eine Last von Ausgabezeilen, bevor es Fehler auf "String oder Binärdaten abgeschnitten" würde. Die spezifischen Zeilenreferenzen in dem Fehler zeigten irgendwo in der Haupt-SELECT-statement oben, aber nach dem Debugging eine Weile, fand ich die Werte, die ich in der Querverweise am Anfang war zu groß und das behielt es.

Aber meine Fragen sind:

  • Wie hat SQL server die Haupt-SELECT-statement ausgeführt, ohne dass die Querverweis-Zeilen eingefügt wurden? Gibt es irgendeine Art von verzögerten Verarbeitung? Lazy Laden von Tabellenvariablen?

  • Warum auf der Erde wird "String oder binäre data abgeschnitten" Nachricht nicht darauf hinweisen, wo es tatsächlich geschieht? Oder mache ich das falsch?

Danke, Ray

BEARBEITEN

Ich denke, es muss etwas mit dem LINKS JOIN zu dem Tisch variieren und dass keine seiner Spalten an der WHERE-Klausel beteiligt sind. SQL server scheint die Vorbereitung der Tabelle verlassen zu haben, bis es benötigt wird (nachdem die INNER JOINs vollständig sind) und an diesem Punkt errorshaft, wenn es bereits die Mehrheit der Ergebnismenge bereit ist, SELECT zu setzen.

Ich habe auch bemerkt, dass die Werte, die erfolgreich in @cross_reference eingegeben werden, in der Ergebnismenge anzeigen, die zurückgegeben wird. Während die Reihen, die es versäumten, zu groß zu sein, nur NULL zeigen.

Nur weil ein Fehler aufgetreten ist, hört das nicht auf, den gespeicherten Proc zu beenden. Sie sehen die Fehlermeldung nicht, da SSMS standardmäßig das Ergebnisraster anzeigt, bis die Abfrage die Verarbeitung beendet hat.

Dies zeigt die Ergebnisse für 10 Sekunden vor dem Umschalten auf die Fehlermeldung:

 RAISERROR('Error',16,1) select top 1000 * from sys.objects so1,sys.objects so2,sys.objects so3 WAITFOR DELAY '00:00:10' 

Wenn Sie möchten, dass der gespeicherte Proc frühzeitig beendet wird, wenn ein Fehler auftritt, müssen Sie frühzeitig ablegen Du könntest deine Einfügung neu schreiben, um so etwas zu sein:

 declare @cross_reference table ( context varchar(20) not null , value1 varchar(10) not null , value2 varchar(10) not null ) insert into @cross_reference (context,value1,value2) values ('map', 'from_value', 'to_value'), ('map', 'from_value', 'to_value'), ('map', 'from_value_xxxxx', 'to_value_xxxxxxx'); if @@ERROR !=0 or @@ROWCOUNT !=3 return 

Oder wenn Sie die Zeilenzähler nicht kennen, ändern Sie die Bedingung auf @@ROWCOUNT = 0

(Oder, natürlich, verwenden Sie TRY / CATCH – aber ich habe nicht viel Code mit ihnen selbst geschrieben, so kann nicht einfach knock out ein Beispiel)

Ihr aktueller Code hat jede Einfügung unabhängig gemacht – also können die Einsätze, die funktionieren, tun können, und diejenigen, die nicht können, Fehlermeldungen erzeugen. Dann geht es weiter mit der Bearbeitung Ihrer abschließenden Abfrage. Da die Tabelle in einer LINKE JOIN verwendet wird, spielt es natürlich keine Frage an der abschließenden Abfrage, ob in der Tabellenvariable Zeilen vorhanden sind.

Ich kann nicht genau reproduzieren, was du beschrieben hast. Eine Sache, die ich sagen würde, konzentriert sich auf das Einfügen von data in die Tabelle var, ist, dass, wenn Sie ANSI_WARNINGS ON dann es sollte Fehler an der Stelle der Einfügen.

dh

 SET ANSI_WARNINGS ON -- Gives the truncation error DECLARE @T1 TABLE (value1 varchar(10) not null) INSERT @T1 VALUES ('1234567890ABC') SET ANSI_WARNINGS OFF -- Does not give the truncation error. "1234567890" will be inserted DECLARE @T1 TABLE (value1 varchar(10) not null) INSERT @T1 VALUES ('1234567890ABC') 

Hast du ANSI_WARNINGS ON oder OFF für die Verbindung?