kry*_*tah 21 sql-server sql-server-2008-r2 linked-server sql-server-2012
我正在通过源服务器上的视图从链接服务器查询数据。该视图必须包含几个标准化列,例如Created
,Modified
和Deleted
,但在这种情况下,源服务器上的表没有任何合适的信息。因此,列被显式转换为它们各自的类型。我更新了视图,从
NULL AS Modified
Run Code Online (Sandbox Code Playgroud)
到
CAST(NULL as DateTime) as Modified
Run Code Online (Sandbox Code Playgroud)
但是,执行此更新后,视图会触发以下错误消息:
消息 7341,级别 16,状态 2,第 3 行无法从链接服务器“”的 OLE DB 提供程序“SQLNCLI11”获取列“(用户生成的表达式)。Expr1002”的当前行值。
我们已经在源服务器上完成了这种“显式转换” - 无需担心,我怀疑这个问题可能与所涉及的服务器版本有关。我们真的不需要应用这个演员表,但感觉更干净。现在我只是好奇为什么会发生这种情况。
服务器版本(来源):
Microsoft SQL Server 2012 - 11.0.5058.0 (X64) 2014 年 5 月 14 日 18:34:29 版权所有 (c) Microsoft Corporation Enterprise Edition(64 位),Windows NT 6.1(内部版本 7601:Service Pack 1)(管理程序)
服务器版本(链接):
Microsoft SQL Server 2008 R2 (SP1) - 10.50.2500.0 (X64) 2011 年 6 月 17 日 00:54:03 版权所有 (c) Microsoft Corporation Enterprise Edition(64 位),Windows NT 6.1(内部版本 7601:Service Pack 1)(管理程序) )
编辑
我刚刚意识到我没有发布所有有问题的专栏是一个错误,我必须为遗漏一个重要细节而道歉。我不知道我怎么没有早点注意到这一点。不过,这个问题仍然存在。
转换为 DateTime 时不会发生错误转换,而是将列转换为 UniqueIdentifier。
这是罪魁祸首:
CAST(NULL AS UniqueIdentifier) AS [GUID]
Run Code Online (Sandbox Code Playgroud)
SQL Server 2008 R2 支持 UniqueIdentifiers,并且如评论中所述,视图执行的查询在链接服务器上运行良好。
Sol*_*zky 13
因此,在意识到CAST
是在本地而不是在远程实例上完成后,我能够重现该错误。我之前曾建议升级到 SP3,希望能解决这个问题(部分原因是无法在 SP3 上重现错误,部分原因是无论如何它都是一个好主意)。但是,现在我可以重现该错误,很明显升级到 SP3 虽然仍然可能是一个好主意,但并不能解决这个问题。而且我还在 SQL Server 2008 R2 RTM 和 2014 SP1 中重现了错误(在所有三种情况下都使用“环回”本地链接服务器)。
看来,这个问题与做在那里执行查询时,或至少其中一部分(S)的它正在执行。我这样说是因为我能够使CAST
操作工作,但只能通过包含对本地 DB 对象的引用:
SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
FROM [Local].[database_name].[dbo].[table_name] rmt
CROSS JOIN (SELECT TOP (1) 1 FROM [sys].[data_spaces]) tmp(dummy);
Run Code Online (Sandbox Code Playgroud)
这确实有效。但以下得到原始错误:
SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
FROM [Local].[database_name].[dbo].[table_name] rmt
CROSS JOIN (VALUES (1)) tmp(dummy);
Run Code Online (Sandbox Code Playgroud)
我猜测,当没有本地引用时,整个查询都会发送到远程系统执行,并且由于某些原因NULL
s 无法转换为UNIQUEIDENTIFIER
,或者NULL
OLE DB 驱动程序可能错误地转换了 s 。
根据我所做的测试,这似乎是一个错误,但我不确定该错误是否在 SQL Server 或 SQL Server Native Client / OLEDB 驱动程序中。但是,转换错误发生在 OLEDB 驱动程序中,因此不一定是从INT
to转换的问题UNIQUEIDENTIFIER
(SQL Server 中不允许的转换),因为驱动程序没有使用 SQL Server 进行转换(SQL Server 也没有允许转换INT
为DATE
,但 OLEDB 驱动程序成功处理,如其中一项测试所示)。
我跑了三个测试。对于成功的两个,我查看了 XML 执行计划,其中显示了正在远程执行的查询。对于这三个,我通过 SQL Profiler 捕获了任何异常或 OLEDB 事件:
事件:
列过滤器:
测试
测试 1
CAST(NULL AS UNIQUEIDENTIFIER)
那个有效SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
, (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
Run Code Online (Sandbox Code Playgroud)
XML 执行计划的相关部分:
SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
FROM [Local].[database_name].[dbo].[table_name] rmt
CROSS JOIN (SELECT TOP (1) 1 FROM [sys].[data_spaces]) tmp(dummy);
Run Code Online (Sandbox Code Playgroud)测试 2
CAST(NULL AS UNIQUEIDENTIFIER)
失败了SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
Run Code Online (Sandbox Code Playgroud)
(注意:我将子查询保留在那里,注释掉了,这样当我比较 XML 跟踪文件时就会减少一个差异)
测试 3
CAST(NULL AS DATE)
那个有效SELECT TOP (2) CAST(NULL AS DATE) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
Run Code Online (Sandbox Code Playgroud)
(注意:我将子查询保留在那里,注释掉了,这样当我比较 XML 跟踪文件时就会减少一个差异)
XML 执行计划的相关部分:
SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
FROM [Local].[database_name].[dbo].[table_name] rmt
CROSS JOIN (VALUES (1)) tmp(dummy);
Run Code Online (Sandbox Code Playgroud)如果您查看测试 #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
to的转换GUID
(请记住,这是在驱动程序中完成的,OLEDB 将其称为“GUID”),这会在 SQL Server 中出现错误,但在 OLEDB 驱动程序中工作正常。远程值不是 NULL
,因此它被替换为文字NULL
,因此<Const ConstValue="NULL" />
.
测试 #2 失败,因此没有执行计划。但是,它确实成功查询了“远程”系统,但无法传回结果集。SQL Profiler 捕获的查询是:
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
, (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
Run Code Online (Sandbox Code Playgroud)
这是在测试#1 中完成的完全相同的查询,但在这里它失败了。还有其他细微的差异,但我无法完全解释 OLEDB 通信。但是,远程字段仍显示为INT
(wType = 3 = adInteger / 四字节有符号整数 / DBTYPE_I4),而“客户端”字段仍显示为GUID
(wType = 72 = adGUID / 全局唯一标识符 / DBTYPE_GUID)。OLE DB 文档没有多大帮助,因为GUID 数据类型转换、DBDATE 数据类型转换和I4 数据类型转换表明从I4转换为GUID或DBDATE不受支持,但DATE
查询有效。
三个测试的 Trace XML 文件位于 PasteBin 上。如果您想查看每个测试与其他测试不同之处的详细信息,您可以将它们保存在本地,然后对它们进行“差异”。这些文件是:
尔格?
该怎么办?考虑到 SQL Native Client --SQLNCLI11
从 SQL Server 2012 起已被弃用,可能只是我在顶部部分提到的解决方法。关于 SQL Server Native Client 主题的大多数 MSDN 页面在最佳:
警告
SQL Server Native Client (SNAC) 在 SQL Server 2012 之后不受支持。避免在新的开发工作中使用 SNAC,并计划修改当前使用它的应用程序。在Microsoft ODBC驱动程序的SQL Server提供了Microsoft SQL Server和微软Azure SQL数据库从Windows的本地连接。
有关更多信息,请参阅:
ODBC ??
我通过以下方式设置了 ODBC 链接服务器:
<DefinedValue>
<ColumnReference Column="Expr1002" />
<ScalarOperator ScalarString="NULL">
<Const ConstValue="NULL" />
</ScalarOperator>
</DefinedValue>
...
<RemoteQuery RemoteSource="Local" RemoteQuery=
"SELECT 1 FROM "TEMPTEST"."sys"."objects" "Tbl1001""
/>
Run Code Online (Sandbox Code Playgroud)
然后尝试:
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
Run Code Online (Sandbox Code Playgroud)
并收到以下错误:
链接服务器“LocalODBC”的 OLE DB 提供程序“MSDASQL”返回消息“不支持请求的转换。”。
消息 7341,级别 16,状态 2,第 53
行无法从链接服务器“LocalODBC”的 OLE DB 提供程序“MSDASQL”获取列“(用户生成的表达式)。Expr1002”的当前行值。
聚苯乙烯
由于它涉及在远程和本地服务器之间传输 GUID,因此通过特殊语法处理非 NULL 值。我在运行时注意到 SQL Profiler 跟踪中的以下 OLE DB 事件信息CAST(0x00 AS UNIQUEIDENTIFIER)
:
SELECT TOP (2) CAST(NULL AS DATE) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
Run Code Online (Sandbox Code Playgroud)
缴费灵
我还通过OPENQUERY
以下查询进行了测试:
<DefinedValue>
<ColumnReference Column="Expr1002" />
<ScalarOperator ScalarString="[Expr1002]">
<Identifier>
<ColumnReference Column="Expr1002" />
</Identifier>
</ScalarOperator>
</DefinedValue>
...
<RemoteQuery RemoteSource="Local" RemoteQuery=
"SELECT TOP (2) NULL "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001""
/>
Run Code Online (Sandbox Code Playgroud)
即使没有本地对象引用,它也成功了。SQL Profiler 跟踪 XML 文件已发布到 PasteBin:
XML 执行计划使用NULL
常量显示它,与测试 #1 中的相同。
归档时间: |
|
查看次数: |
6131 次 |
最近记录: |