该视图必须包含一些标准化列,例如Created,Modified和Deleted,但在这种情况下,源服务器上的表没有任何合适的信息.因此,列显式地转换为它们各自的类型.我更新了视图,更改了一列
NULL AS Modified
至
CAST(NULL as DateTime) as Modified
但是,执行此更新后,视图将触发以下错误消息:
Msg 7341,Level 16,State 2,Line 3
Cannot get the current row value of column “(user generated expression).Expr1002” from OLE DB provider “sqlNCLI11” for linked server “”.
我们通常在原始服务器上完成了这个“显式转换” – 更改而不用担心,我怀疑问题可能与所涉及的服务器版本有关.我们真的不需要应用这个演员阵容,但感觉更干净.现在我只是好奇为什么会这样.
服务器版本(来源):
Microsoft sql Server 2012 – 11.0.5058.0 (X64) May 14 2014 18:34:29 Copyright (c) Microsoft Corporation Enterprise Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor)
服务器版本(链接):
Microsoft sql Server 2008 R2 (SP1) – 10.50.2500.0 (X64) Jun 17 2011 00:54:03 Copyright (c) Microsoft Corporation Enterprise Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1) (Hypervisor)
编辑
我刚刚意识到我没有发布所有相关栏目而犯了一个错误,我必须为遗漏重要细节而道歉.我不知道我怎么不早点注意到这一点.但问题仍然存在.
转换为DateTime时不会发生错误的强制转换,但会将一个列强制转换为UniqueIdentifier.
这是罪魁祸首:
CAST(NULL AS UniqueIdentifier) AS [GUID]
sql Server 2008 R2支持UniqueIdentifier,并且如注释中所述,视图执行的查询在链接服务器上运行正常.
解决方法
似乎这个问题与执行查询的位置有关,或者至少在执行查询的部分时.我这样说是因为我能够使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);
这确实有效.但以下是原始错误:
SELECT rmt.*,CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID] FROM [Local].[database_name].[dbo].[table_name] rmt CROSS JOIN (VALUES (1)) tmp(dummy);
我猜测,当没有本地引用时,整个查询将被运送到远程系统执行,并且由于某种原因,NULL无法转换为UNIQUEIDENTIFIER,或者OLE DB驱动程序错误地转换了NULL.
基于我所做的测试,这似乎是一个错误,但我不确定该错误是在sql Server还是sql Server Native Client / OLEDB驱动程序中.但是,OLEDB驱动程序中发生转换错误,因此不一定是从INT转换为UNIQUEIDENTIFIER(sql Server中不允许的转换)的问题,因为驱动程序未使用sql Server进行转换(sql Server也是如此)不允许将INT转换为DATE,但OLEDB驱动程序成功处理,如其中一个测试所示.
我跑了三次测试.对于成功的两个,我查看了XML执行计划,它显示了正在远程执行的查询.对于这三个,我通过sql事件探查器捕获了任何异常或OLEDB事件:
事件:
>错误和警告
> OLEDB
>全部
> Tsql
>所有除外:
> sql:StmtRecompile
> XQuery静态类型
列过滤器:
> ApplicationName
>不喜欢%Intellisense%
> SPID
>大于或等于50
测试
>测试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;
XML执行计划的相关部分:
<DefinedValue> <ColumnReference Column="Expr1002" /> <ScalarOperator ScalarString="NULL"> <Const ConstValue="NULL" /> </ScalarOperator> </DefinedValue> ... <RemoteQuery RemoteSource="Local" RemoteQuery= "SELECT 1 FROM "TEMPTEST"."sys"."objects" "Tbl1001"" />
>测试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;
(注意:我将子查询保留在那里,注释掉了,这样当我比较XML跟踪文件时,它会少一点差异)
>测试3
> CAST(NULL AS DATE)有效
SELECT TOP (2) CAST(NULL AS DATE) AS [Something] --,它会少一点差异)XML执行计划的相关部分:
<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"" />如果你看看测试#3,它在“远程”系统上进行SELECT TOP(2)NULL. sql事件探查器跟踪显示此远程字段的数据类型实际上是INT.跟踪还显示客户端上的字段(即我运行查询的位置)是DATE,如预期的那样.从INT转换为DATE,这将在sql Server中出现错误,在OLEDB驱动程序中正常工作.远程值为NULL,因此直接返回,因此< ColumnReference Column =“Expr1002”/>.
如果你看一下Test#1,它就会在“远程”系统上做一个SELECT 1. sql事件探查器跟踪显示此远程字段的数据类型实际上是INT.跟踪还显示客户端上的字段(即我运行查询的位置)是GUID,如预期的那样.从INT转换为GUID(请记住,这是在驱动程序中完成的,而OLEDB将其称为“GUID”),在OLEDB驱动程序中正常工作.远程值不是NULL,因此它被替换为文字NULL,因此< Const ConstValue =“NULL”/>.
测试#2失败,因此没有执行计划.但是,它确实成功查询了“远程”系统,但是无法传回结果集. sql事件探查器捕获的查询是:
SELECT TOP (2) NULL "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001"这就是在测试#1中完成的完全相同的查询,但在这里它失败了.还有其他细微差别,但我无法完全理解OLEDB通信.但是,远程字段仍显示为INT(wType = 3 = adInteger /四字节有符号整数/ DBTYPE_I4),而“client”字段仍显示为GUID(wType = 72 = adGUID /全局唯一标识符/ DBTYPE_GUID). OLE DB文档没有多大帮助,因为GUID Data Type Conversions,DBDATE Data Type Conversions和I4 Data Type Conversions显示不支持从I4转换为GUID或DBDATE,但DATE查询有效.
三个测试的Trace XML文件位于PasteBin上.如果要查看每个测试与其他测试的不同之处的详细信息,可以在本地保存它们,然后对它们进行“差异”.文件是:
> NullGuidSuccess.xml
> NullGuidError.xml
> NullDateSuccess.xmlERGO?
该怎么办?可能只是我在上一节中提到的解决方法,因为从sql Server 2012开始不推荐使用sql Native Client – sqlNCLI11.关于sql Server Native Client主题的大多数MSDN页面都有以下注意事项:顶端:
Warning
sql Server Native Client (SNAC) is not supported beyond sql Server 2012. Avoid using SNAC in new development work,and plan to modify applications that currently use it. The 07006 provides native connectivity from Windows to Microsoft sql Server and Microsoft Azure sql Database.
有关详细信息,请参阅:
> SQL Server Native Client
> Installing SQL Server Native ClientODBC?
我通过以下方式设置ODBC链接服务器:
EXEC master.dbo.sp_addlinkedserver @server = N'LocalODBC',@srvproduct=N'{my_server_name}',@provider=N'MSDAsql',@provstr=N'Driver={sql Server};Server=(local);Trusted_Connection=Yes;'; EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'LocalODBC',@useself=N'True',@locallogin=NULL,@rmtuser=NULL,@rmtpassword=NULL;然后尝试:
SELECT CAST(NULL AS UNIQUEIDENTIFIER) AS [Something] FROM [LocalODBC].[tempdb].[sys].[objects] rmt;并收到以下错误:
OLE DB provider “MSDAsql” for linked server “LocalODBC” returned message “Requested conversion is not supported.”.
Msg 7341,Line 53
Cannot get the current row value of column “(user generated expression).Expr1002” from OLE DB provider “MSDAsql” for linked server “LocalODBC”.附:
由于它涉及在远程服务器和本地服务器之间传输GUID,因此通过特殊语法处理非NULL值.当我运行CAST(0x00 AS UNIQUEIDENTIFIER)时,我在sql事件探查器跟踪中注意到以下OLE DB事件信息:
<RemoteQuery RemoteSource="Local" RemoteQuery= "SELECT {guid'00000000-0000-0000-0000-000000000000'} "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001"" />P.P.S.
我还通过OPENQUERY使用以下查询进行了测试:
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something] --,(SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl] FROM OPENQUERY([Local],N'SELECT 705 AS [dummy] FROM [TEMPTEST].[sys].[objects];') rmt;它成功了,即使没有本地对象引用. sql事件探查器跟踪XML文件已发布到PasteBin:
XML执行计划使用NULL常量显示它,与测试#1中的相同.