Ich frage Daten von einem Verbindungsserver über eine Ansicht auf dem Ursprungsserver ab. Die Ansicht hat ein paar standardisierte Spalten enthält, wie zum Beispiel Created
, Modified
und Deleted
, aber in diesem Fall wird die Tabelle auf dem Quellserver hat keine geeigneten Informationen. Die Spalten werden daher explizit in ihre jeweiligen Typen umgewandelt. Ich habe die Ansicht aktualisiert und eine Spalte von geändert
NULL AS Modified
zu
CAST(NULL as DateTime) as Modified
Nach der Durchführung dieses Updates wird jedoch die folgende Fehlermeldung von der Ansicht ausgelöst:
Meldung 7341, Ebene 16, Status 2, Zeile 3 Der aktuelle Zeilenwert der Spalte "(vom Benutzer generierter Ausdruck) .Expr1002" kann nicht vom OLE DB-Anbieter "SQLNCLI11" für Verbindungsserver "" abgerufen werden.
Wir haben diesen "expliziten Cast" -Austausch im Allgemeinen ohne Bedenken auf dem Ursprungsserver durchgeführt, und ich vermute, dass das Problem mit der Version der beteiligten Server zusammenhängt. Wir wissen nicht wirklich brauchen diese Besetzung bewerben, aber es fühlt sich sauberer. Im Moment bin ich nur gespannt, warum das so ist.
Serverversion (Ursprung):
Microsoft SQL Server 2012 - 11.0.5058.0 (X64) 14. Mai 2014, 18:34:29 Uhr Copyright (c) Microsoft Corporation Enterprise Edition (64-Bit) unter Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor)
Serverversion (verlinkt):
Microsoft SQL Server 2008 R2 (SP1) - 10.50.2500.0 (X64) 17. Juni 2011 00:54:03 Copyright (c) Microsoft Corporation Enterprise Edition (64-Bit) unter Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor )
Bearbeiten
Ich habe gerade erkannte ich einen Fehler gemacht , indem nicht alle Spalten in Frage veröffentlichen, und ich muss für das Weglassen ein wichtiges Detail entschuldigen. Ich weiß nicht, wie ich das früher nicht bemerkt habe. Die Frage bleibt jedoch weiterhin offen.
Die fehlerhafte Umwandlung erfolgt nicht bei der Umwandlung in DateTime, sondern bei der Umwandlung einer Spalte in UniqueIdentifier.
Das ist der Täter:
CAST(NULL AS UniqueIdentifier) AS [GUID]
UniqueIdentifiers werden in SQL Server 2008 R2 unterstützt. Wie in den Kommentaren erwähnt, wird die von der Ansicht ausgeführte Abfrage auf dem Verbindungsserver ordnungsgemäß ausgeführt.
Danish_Norwegian_CI_AS
und der Verbindungsserver hat die SortierungSQL_Danish_Pref_CP1_CI_AS
, aber dieCOLLATE
Klausel kann nicht aufDateTime
Spalten angewendet werden , so dass ich nicht viel weiter komme!select Null from ...
in WITH oder verschachtelten Abfrage undCAST
in einem anderen?INT
Sie den Datentyp dadurch geändert. Ich weiß nicht, warum das Ihnen diese Fehlermeldung geben würde.Antworten:
Daher konnte ich den Fehler reproduzieren, nachdem ich festgestellt hatte, dass
CAST
er lokal und nicht auf der Remote-Instanz ausgeführt wurde. Ich hatte zuvor empfohlen, auf SP3 zu wechseln, in der Hoffnung, dies zu beheben (teilweise, weil der Fehler auf SP3 nicht reproduziert werden kann, und teilweise, weil es trotzdem eine gute Idee ist). Jetzt, da ich den Fehler reproduzieren kann, ist es klar, dass das Hochrüsten auf SP3, obwohl es wahrscheinlich immer noch eine gute Idee ist, dies nicht beheben wird. Außerdem habe ich den Fehler in SQL Server 2008 R2 RTM und 2014 SP1 reproduziert (wobei in allen drei Fällen ein lokaler "Loopback" -Verbindungsserver verwendet wurde).Es scheint, dass dieses Problem damit zusammenhängt, wo die Abfrage ausgeführt wird oder zumindest, wo Teile davon ausgeführt werden. Ich sage dies, weil ich die
CAST
Operation zum Laufen bringen konnte, aber nur durch Einfügen eines Verweises auf ein lokales DB-Objekt:Das funktioniert tatsächlich. Aber das Folgende bekommt den ursprünglichen Fehler:
Ich vermute, dass, wenn es keine lokalen Verweise gibt, die gesamte Abfrage an das Remotesystem gesendet wird, um ausgeführt zu werden, und aus irgendeinem Grund
NULL
nicht konvertiert werdenUNIQUEIDENTIFIER
kann oder möglicherweiseNULL
vom OLE DB-Treiber falsch übersetzt wird.Basierend auf den Tests, die ich durchgeführt habe, scheint dies ein Fehler zu sein, aber ich bin nicht sicher, ob der Fehler in SQL Server oder dem SQL Server Native Client / OLEDB-Treiber vorliegt. Der Konvertierungsfehler tritt jedoch im OLEDB-Treiber auf und ist daher nicht unbedingt ein Problem beim Konvertieren von
INT
nachUNIQUEIDENTIFIER
(eine Konvertierung, die in SQL Server nicht zulässig ist), da der Treiber SQL Server nicht für Konvertierungen verwendet (SQL Server ebenfalls nicht) KonvertierungINT
in zulassenDATE
, der OLEDB-Treiber erledigt dies jedoch erfolgreich (wie in einem der Tests gezeigt).Ich habe drei Tests durchgeführt. Für die beiden, die erfolgreich waren, habe ich mir die XML-Ausführungspläne angesehen, die die Abfrage zeigen, die remote ausgeführt wird. Für alle drei habe ich Ausnahmen oder OLEDB-Ereignisse über SQL Profiler erfasst:
Veranstaltungen:
Spaltenfilter:
DIE TESTS
Test 1
CAST(NULL AS UNIQUEIDENTIFIER)
das funktioniertRelevanter Teil des XML-Ausführungsplans:
Test 2
CAST(NULL AS UNIQUEIDENTIFIER)
das scheitert(Anmerkung: Ich habe die Unterabfrage dort gespeichert und auskommentiert, damit es einen Unterschied weniger gibt, wenn ich die XML-Tracedateien vergleiche.)
Test 3
CAST(NULL AS DATE)
das funktioniert(Anmerkung: Ich habe die Unterabfrage dort gespeichert und auskommentiert, damit es einen Unterschied weniger gibt, wenn ich die XML-Tracedateien vergleiche.)
Relevanter Teil des XML-Ausführungsplans:
Wenn Sie sich Test Nr. 3 ansehen, handelt es sich um einen Test
SELECT TOP (2) NULL
auf dem "Remote" -System. Die SQL Profiler-Ablaufverfolgung zeigt, dass der Datentyp dieses Remote-Felds tatsächlich istINT
. Die Ablaufverfolgung zeigt auch, dass das Feld auf der Clientseite (dh von wo aus ich die Abfrage ausführe)DATE
wie erwartet ist. Die Konvertierung vonINT
nachDATE
, die in SQL Server einen Fehler verursacht, funktioniert im OLEDB-Treiber einwandfrei. Der entfernte Wert istNULL
, also wird er direkt zurückgegeben, daher der<ColumnReference Column="Expr1002" />
.Wenn Sie sich Test Nr. 1 ansehen, handelt es sich um einen Test
SELECT 1
auf dem "Remote" -System. Die SQL Profiler-Ablaufverfolgung zeigt, dass der Datentyp dieses Remote-Felds tatsächlich istINT
. Die Ablaufverfolgung zeigt auch, dass das Feld auf der Clientseite (dh von wo aus ich die Abfrage ausführe)GUID
wie erwartet ist. Die Konvertierung vonINT
nachGUID
(denken Sie daran, dies erfolgt innerhalb des Treibers, und OLEDB nennt es "GUID"), was in SQL Server einen Fehler hervorruft, funktioniert innerhalb des OLEDB-Treibers einwandfrei. Der entfernte Wert ist nichtNULL
, daher wird er durch ein Literal ersetztNULL
, daher der<Const ConstValue="NULL" />
.Test Nr. 2 schlägt fehl, sodass kein Ausführungsplan vorhanden ist. Das "entfernte" System wird jedoch erfolgreich abgefragt, die Ergebnismenge kann jedoch nicht zurückgegeben werden. Die Abfrage, die SQL Profiler erfasst hat, lautet:
Das ist genau die gleiche Abfrage, die in Test 1 durchgeführt wird, aber hier schlägt sie fehl. Es gibt noch andere kleine Unterschiede, aber ich kann die OLEDB-Mitteilung nicht vollständig interpretieren. Das entfernte Feld wird jedoch weiterhin als
INT
(wType = 3 = adInteger / Vier-Byte-Ganzzahl mit Vorzeichen / DBTYPE_I4) angezeigt, während das Feld "client" weiterhin alsGUID
(wType = 72 = adGUID / global eindeutiger Bezeichner / DBTYPE_GUID) angezeigt wird. Die OLE DB-Dokumentation hilft nicht viel, da GUID-Datentypkonvertierungen , DBDATE-Datentypkonvertierungen und I4-Datentypkonvertierungen zeigen, dass die Konvertierung von I4 in GUID oder DBDATE nicht unterstützt wird, dieDATE
Abfrage jedoch funktioniert.Die Trace-XML-Dateien für die drei Tests befinden sich in PasteBin. Wenn Sie die Details sehen möchten, in denen sich die einzelnen Tests von den anderen unterscheiden, können Sie sie lokal speichern und dann "diff" auf sie anwenden. Die Dateien sind:
ERGO?
Was tun? Wahrscheinlich nur die Problemumgehung, die ich im oberen Abschnitt notiert habe,
SQLNCLI11
da der SQL Server Native Client - - ab SQL Server 2012 veraltet ist. Die meisten MSDN-Seiten zum Thema SQL Server Native Client haben den folgenden Hinweis am oben:Weitere Informationen finden Sie unter:
ODBC ??
Ich richte einen ODBC-Verbindungsserver ein über:
Und dann versucht:
und erhielt den folgenden Fehler:
PS
Beim Transport von GUIDs zwischen entfernten und lokalen Servern werden Nicht-NULL-Werte über eine spezielle Syntax behandelt. Ich habe beim Ausführen die folgenden OLE DB-Ereignisinformationen in der SQL Profiler-Ablaufverfolgung festgestellt
CAST(0x00 AS UNIQUEIDENTIFIER)
:PPS
Ich habe auch über
OPENQUERY
mit der folgenden Abfrage getestet :und es gelang, auch ohne die lokale Objektreferenz. Die SQL Profiler-Trace-XML-Datei wurde in PasteBin gepostet unter:
NullGuidSuccessOPENQUERY.xml
Der XML-Ausführungsplan zeigt dies unter Verwendung einer
NULL
Konstante wie in Test 1.quelle
Es gibt nur eine hässliche Problemumgehung - verwenden Sie
'1900-01-01'
stattdessen eine Datumskonstante wienull
.Nach dem Import können Sie die Spalten mit
1900-01-01
back to Null aktualisieren .Dies ist eine Art SQL 2012-Feature / Bug wie hier .
Bearbeiten: Ersetzt
1900-00-00
durch ein gültiges Datum1900-01-01
gemäß @a_horse_with_no_name Kommentar unten.quelle
uniqueidentifier
Kolumne ist. Oder könnte es vielleicht angepasst werden - so etwas wieCAST('00000000-0000-0000-0000-000000000000' AS UniqueIdentifier) AS [GUID]
vielleicht?1900-00-00
ist ein ungültiges Datum und wird nicht akzeptiert.Das Problem hängt mit Datentypkonvertierungen zusammen (wie in den Kommentaren angeklickt).
Folgendes berücksichtigen:
Beachten Sie, dass das
NullColumn
vom Typ istint
. SQL Server konvertiert keineint
Werte inuniqueidentifier
. DieseSELECT
Anweisung schlägt bei einer Datentypkonvertierung fehl:Während dieser bestimmte Wert (NULL) in eine GUID umgewandelt werden kann, gibt SQL Server den Fehler basierend auf der Datentypkonvertierung aus, bevor er sich die spezifischen Werte ansieht. Stattdessen müssen Sie ein mehrstufiges tun
CAST
Betrieb Änderung der impliziten gehenint
zu einem Datentyp, der sauber in umgewandelt werden kannuniqueidentifer
--which Mittel zuerst Gießenvarchar
dann zuuniqueidentifier
:quelle
Das OP kann letztendlich entscheiden, ob dies eine angemessene Antwort ist.
Ich habe keinen "absoluten" Beweis, aber ich "vermute", dass das Problem auf die Tatsache zurückzuführen ist, dass ein UniqueIdentifer serverabhängig ist und der Anbieter möglicherweise Schwierigkeiten hat, herauszufinden, von welchem Server (lokal oder remote) dieser UniqueIdentifier stammt, obwohl dies der Fall ist Null. Aus diesem Grund können Sie in diesem Szenario wahrscheinlich jeden anderen Datentyp erfolgreich übertragen, jedoch keine eindeutige Kennung. Datentypen, die 'server'-abhängig sind, wie UNIQUEIDENTIFIERS und DATETIMEOFFSET, geben Ihnen den Fehler, auf den Sie stoßen.
Die Verwendung von OPENQUERY anstelle von 4-teiligen Namen funktioniert.
quelle
Uniqueidentifier
und ob du serverabhängig bistDateTimeOffset
? Haben Sie Quellen dafür?Problemumgehung: Die akzeptierte Antwort scheint darauf hinzudeuten, dass die Konvertierung lokal erfolgen muss, da der OLEDB-Treiber dies nicht unterstützt.
Ich denke, eine einfache Problemumgehung (zumindest im Fall meiner Abfrage,
uniqueidentifier
bei der im Basisfall eines rekursiven CTE ein Nullwert ausgewählt wird) besteht darin, eine Nullvariable zu deklarieren:quelle