Я запрашиваю данные со связанного сервера через просмотр на исходном сервере. Представление должно включать пару стандартизированных столбцов, таких как Created
, Modified
и Deleted
, но в этом случае таблица на исходном сервере не имеет подходящей информации. Поэтому столбцы явно приводятся к своим соответствующим типам. Я обновил вид, изменив столбец с
NULL AS Modified
в
CAST(NULL as DateTime) as Modified
Однако после выполнения этого обновления представление вызывает следующее сообщение об ошибке:
Сообщение 7341, уровень 16, состояние 2, строка 3 Не удается получить текущее значение строки столбца "(сгенерированное пользователем выражение) .Expr1002" от поставщика OLE DB "SQLNCLI11" для связанного сервера "".
Мы сделали это «явное приведение» -обмена, как правило, на исходном сервере, не беспокоясь, и я подозреваю, что проблема может быть связана с версией задействованных серверов. Нам не нужно применять этот актерский состав, но он кажется чище. Прямо сейчас мне просто интересно, почему это происходит.
Версия сервера (источник):
Microsoft SQL Server 2012 - 11.0.5058.0 (X64) 14 мая 2014 г. 18:34:29 Авторское право (c) Microsoft Corporation Enterprise Edition (64-разрядная версия) в Windows NT 6.1 (сборка 7601: пакет обновления 1) (гипервизор)
Версия сервера (связана):
Microsoft SQL Server 2008 R2 (SP1) - 10.50.2500.0 (X64) 17 июня 2011 г. 00:54:03 Авторское право (c) Microsoft Corporation Enterprise Edition (64-разрядная версия) в Windows NT 6.1 (сборка 7601: пакет обновления 1) (гипервизор) )
Редактировать
Я только что понял, что сделал ошибку, не разместив все столбцы, о которых идет речь, и я должен извиниться за то, что пропустил важную деталь. Я не знаю, как я не заметил этого раньше. Вопрос все еще остается, хотя.
Ошибочное приведение происходит не с приведением к DateTime, а с приведением столбца к UniqueIdentifier.
Это виновник:
CAST(NULL AS UniqueIdentifier) AS [GUID]
UniqueIdentifiers поддерживаются в SQL Server 2008 R2, и, как упоминалось в комментариях, запрос, выполняемый представлением, прекрасно работает на связанном сервере.
Danish_Norwegian_CI_AS
а связанный сервер имеет параметры сортировкиSQL_Danish_Pref_CP1_CI_AS
, ноCOLLATE
предложение не может быть применено кDateTime
столбцам, поэтому я не получил много дальше!select Null from ...
в WITH или во вложенном запросе иCAST
в другом?INT
так, как вы изменили тип данных. Я не знаю, почему это даст вам это сообщение об ошибке, хотя.Ответы:
Итак, я смог воспроизвести ошибку, поняв, что
CAST
делается локально, а не на удаленном экземпляре. Ранее я рекомендовал перейти на SP3 в надежде исправить это (частично из-за невозможности воспроизвести ошибку на SP3, а частично из-за того, что это хорошая идея, независимо от того). Тем не менее, теперь, когда я могу воспроизвести ошибку, становится ясно, что переход на SP3, хотя все еще, вероятно, хорошая идея, не собирается это исправить. И я также воспроизвел ошибку в SQL Server 2008 R2 RTM и 2014 SP1 (с использованием «закольцованного» локального связанного сервера во всех трех случаях).Кажется , что эта проблема связана с , где запрос выполняется, или , по крайней мере там , где часть (части) из него выполняются. Я говорю это потому, что смог заставить
CAST
работать операцию, но только включив ссылку на локальный объект БД:Это на самом деле работает. Но следующее получает оригинальную ошибку:
Я предполагаю, что когда нет локальных ссылок, весь запрос отправляется в удаленную систему для выполнения, и по какой-то причине
NULL
s не может быть преобразованоUNIQUEIDENTIFIER
или, возможно,NULL
неправильно переводится драйвером OLE DB.Исходя из проведенного мною тестирования, это может показаться ошибкой, но я не уверен, что ошибка в SQL Server или в драйвере собственного клиента SQL Server / OLEDB. Однако ошибка преобразования происходит в драйвере OLEDB, и поэтому не обязательно является проблемой преобразования из
INT
вUNIQUEIDENTIFIER
(преобразование, которое не разрешено в SQL Server), поскольку драйвер не использует SQL Server для выполнения преобразований (SQL Server также не делает этого). позволяют преобразовыватьINT
вDATE
, но ручки водителя OLEDB , который успешно, как показано в одном из тестов).Я провел три теста. Для двух успешных я посмотрел на планы выполнения XML, которые показывают запрос, который выполняется удаленно. Для всех трех я захватил любые исключения или события OLEDB через SQL Profiler:
Мероприятия:
Фильтры колонок:
ТЕСТЫ
Тест 1
CAST(NULL AS UNIQUEIDENTIFIER)
это работаетСоответствующая часть плана выполнения XML:
Тест 2
CAST(NULL AS UNIQUEIDENTIFIER)
что терпит неудачу(примечание: я сохранил подзапрос, закомментированный, чтобы при сравнении файлов трассировки XML разница была на один раз меньше)
Тест 3
CAST(NULL AS DATE)
это работает(примечание: я сохранил подзапрос, закомментированный, чтобы при сравнении файлов трассировки XML разница была на один раз меньше)
Соответствующая часть плана выполнения XML:
Если вы посмотрите на тест № 3, он выполняется
SELECT TOP (2) NULL
на «удаленной» системе. Трассировка SQL Profiler показывает, что тип данных этого удаленного поля на самом делеINT
. Трассировка также показывает, что поле на стороне клиента (то есть, откуда я запускаю запрос)DATE
, как и ожидалось. Преобразование изINT
вDATE
, что приведет к ошибке в SQL Server, прекрасно работает в драйвере OLEDB. Удаленное значение естьNULL
, поэтому оно возвращается напрямую, отсюда и<ColumnReference Column="Expr1002" />
.Если вы посмотрите на Тест № 1, он выполняется
SELECT 1
на «удаленной» системе. Трассировка SQL Profiler показывает, что тип данных этого удаленного поля на самом делеINT
. Трассировка также показывает, что поле на стороне клиента (то есть, откуда я запускаю запрос)GUID
, как и ожидалось. Преобразование изINT
вGUID
(помните, что это делается в драйвере, и OLEDB называет его «GUID»), что приведет к ошибке в SQL Server, прекрасно работает в драйвере OLEDB. Удаленного значения нетNULL
, поэтому оно заменяется литераломNULL
, отсюда и<Const ConstValue="NULL" />
.Тест № 2 не пройден, поэтому нет плана выполнения. Однако он успешно запрашивает «удаленную» систему, но просто не может вернуть набор результатов. Запрос, который захватил SQL Profiler:
Это тот же самый запрос, который выполняется в Тесте № 1, но здесь он терпит неудачу. Существуют и другие незначительные различия, но я не могу полностью интерпретировать сообщение OLEDB. Однако удаленное поле по-прежнему отображается как
INT
(wType = 3 = adInteger / четырехбайтовое целое число со знаком / DBTYPE_I4), а поле «клиент» по-прежнему отображается какGUID
(wType = 72 = adGUID / глобально уникальный идентификатор / DBTYPE_GUID). Документации OLE DB не очень помогает , как GUID типа данных преобразований , DBDATE Тип данных преобразований и I4 Тип данных преобразований показывают , что преобразование из I4 либо GUID или DBDATE не поддерживается, все жеDATE
работы запроса.XML-файлы трассировки для трех тестов находятся в PasteBin. Если вы хотите увидеть детали того, где каждый тест отличается от других, вы можете сохранить их локально, а затем выполнить «сравнение» с ними. Файлы:
ЭРГО?
Что с этим делать? Вероятно, это просто обходной путь, который я отметил в верхнем разделе, учитывая, что собственный клиент SQL -
SQLNCLI11
- не рекомендуется на SQL Server 2012. Большинство страниц MSDN по теме собственного клиента SQL Server имеют следующее уведомление на верх:Для получения дополнительной информации, пожалуйста, смотрите:
ODBC ??
Я установил ODBC Linked Server через:
А потом попробовал:
и получил следующую ошибку:
PS
Поскольку это относится к транспортировке GUID между удаленными и локальными серверами, значения, отличные от NULL, обрабатываются с помощью специального синтаксиса. Я заметил следующую информацию о событии OLE DB в трассировке SQL Profiler при запуске
CAST(0x00 AS UNIQUEIDENTIFIER)
:PPS
Я также проверил через
OPENQUERY
следующий запрос:и это удалось, даже без ссылки на локальный объект. Файл XML трассировки SQL Profiler был опубликован в PasteBin по адресу:
NullGuidSuccessOPENQUERY.xml
План выполнения XML показывает его с использованием
NULL
константы, как в Тесте № 1.источник
Есть только уродливый обходной путь - используйте некоторую константу даты как
'1900-01-01'
вместоnull
.После импорта вы можете обновить столбцы
1900-01-01
обратно на Null.Это своего рода особенность / ошибка SQL 2012, как здесь .
Изменить: заменено
1900-00-00
действительной датой1900-01-01
согласно комментарию @a_horse_with_no_name ниже.источник
uniqueidentifier
столбец. Или, может быть, это может быть адаптировано - что-то вродеCAST('00000000-0000-0000-0000-000000000000' AS UniqueIdentifier) AS [GUID]
, возможно?1900-00-00
является недействительной датой и не будет принята.Проблема связана с преобразованием типов данных (как отмечено в комментариях).
Учтите следующее:
Обратите внимание, что
NullColumn
это типаint
. SQL Server не любит преобразовыватьint
значения вuniqueidentifier
. ЭтотSELECT
оператор потерпит неудачу при преобразовании типов данных:Хотя это конкретное значение (NULL) можно преобразовать в GUID, SQL Server выдает ошибку, основанную на преобразовании типов данных, прежде чем даже смотреть на конкретные значения. Вместо этого вам нужно будет выполнить многошаговую
CAST
операцию, чтобы изменить неявныйint
тип данных, который может быть чисто преобразован вuniqueidentifer
-, что означает приведение сначала кvarchar
потомuniqueidentifier
:источник
ФП в конечном итоге может решить, является ли это правильным ответом.
У меня нет «абсолютных» доказательств, но я «подозреваю», что проблема связана с тем фактом, что UniqueIdentifer зависит от сервера, и, возможно, провайдеру сложно определить, с какого сервера (локального или удаленного) получить этот uniqueidentifier, даже если он значение NULL. Вот почему в этом сценарии вы, вероятно, можете успешно преобразовать любой другой тип данных, но не uniqueidentifier. Типы данных, которые зависят от сервера, такие как UNIQUEIDENTIFIERS и DATETIMEOFFSET, сообщат вам об ошибке, с которой вы столкнулись.
Использование OPENQUERY вместо названия из 4-х частей работает.
источник
Uniqueidentifier
иDateTimeOffset
быть сервер-зависимым? Есть ли у вас источники для этого?Обходной путь: принятый ответ кажется, указывает, что преобразование должно происходить локально, потому что драйвер OLEDB не поддерживает его.
Поэтому я думаю, что простой обходной путь (по крайней мере, в случае моего запроса, который выбирает нуль
uniqueidentifier
в базовом случае рекурсивного CTE) - это объявить нулевую переменную:источник