Vì vậy, tôi đã có thể tái tạo lỗi sau khi nhận ra rằng việc CAST
đó đang được thực hiện cục bộ chứ không phải trên trường hợp từ xa. Trước đây tôi đã đề nghị chuyển lên SP3 với hy vọng sửa lỗi này (một phần do không thể tái tạo lỗi trên SP3 và một phần do đó là một ý tưởng tốt bất kể). Tuy nhiên, bây giờ tôi có thể tái tạo lỗi, rõ ràng việc chuyển lên SP3, trong khi vẫn có thể là một ý tưởng tốt, sẽ không khắc phục điều này. Và tôi cũng đã tái tạo lỗi trong SQL Server 2008 R2 RTM và 2014 SP1 (sử dụng Máy chủ được liên kết cục bộ "loop-back" trong cả ba trường hợp).
Có vẻ như vấn đề này liên quan đến nơi truy vấn đang thực thi hoặc ít nhất là nơi một phần của nó đang thực thi. Tôi nói điều này bởi vì tôi có thể làm cho CAST
hoạt động hoạt động, nhưng chỉ bằng cách bao gồm một tham chiếu đến một đối tượng DB cục bộ:
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);
Điều đó thực sự hoạt động. Nhưng sau đây nhận được lỗi ban đầu:
SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
FROM [Local].[database_name].[dbo].[table_name] rmt
CROSS JOIN (VALUES (1)) tmp(dummy);
Tôi đoán rằng khi không có tài liệu tham khảo cục bộ, toàn bộ truy vấn sẽ được chuyển đến hệ thống từ xa để thực thi và vì một số lý do NULL
không thể chuyển đổi thành UNIQUEIDENTIFIER
, hoặc có lẽ NULL
do trình điều khiển OLE DB dịch sai.
Dựa trên thử nghiệm mà tôi đã thực hiện, đây có thể là một lỗi, nhưng tôi không chắc liệu lỗi đó có nằm trong SQL Server hay trình điều khiển SQLB Client Client / OLEDB không. Tuy nhiên, lỗi chuyển đổi xảy ra trong trình điều khiển OLEDB và do đó không nhất thiết là vấn đề chuyển đổi từ INT
sang UNIQUEIDENTIFIER
(một chuyển đổi không được phép trong SQL Server) do trình điều khiển không sử dụng SQL Server để thực hiện chuyển đổi (SQL Server cũng không cho phép chuyển đổi INT
sang DATE
, nhưng trình điều khiển OLEDB xử lý thành công, như thể hiện trong một trong các thử nghiệm).
Tôi đã chạy ba bài kiểm tra. Đối với hai người đã thành công, tôi đã xem xét các kế hoạch thực hiện XML hiển thị truy vấn đang được thực hiện từ xa. Đối với cả ba, tôi đã nắm bắt bất kỳ Ngoại lệ hoặc sự kiện OLEDB nào thông qua SQL Profiler:
Sự kiện:
- Lỗi và cảnh báo
- Chú ý
- ngoại lệ
- Cảnh báo thực thi
- Thông báo lỗi người dùng
- OLEDB
- TSQL
- tất cả ngoại trừ :
- SQL: StmtRecompile
- Kiểu tĩnh XQuery
Bộ lọc cột:
- Tên ứng dụng
- KHÔNG THÍCH % Intellisense%
- SPID
CÁC BÀI KIỂM TRA
Kiểm tra 1
CAST(NULL AS UNIQUEIDENTIFIER)
nó hoạt động
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
, (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
Phần có liên quan của kế hoạch thực hiện XML:
<DefinedValue>
<ColumnReference Column="Expr1002" />
<ScalarOperator ScalarString="NULL">
<Const ConstValue="NULL" />
</ScalarOperator>
</DefinedValue>
...
<RemoteQuery RemoteSource="Local" RemoteQuery=
"SELECT 1 FROM "TEMPTEST"."sys"."objects" "Tbl1001""
/>
Kiểm tra 2
CAST(NULL AS UNIQUEIDENTIFIER)
thất bại
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
(lưu ý: Tôi đã giữ truy vấn con trong đó, nhận xét, để nó sẽ khác biệt ít hơn khi tôi so sánh các tệp theo dõi XML)
Bài kiểm tra 3
CAST(NULL AS DATE)
nó hoạt động
SELECT TOP (2) CAST(NULL AS DATE) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
(lưu ý: Tôi đã giữ truy vấn con trong đó, nhận xét, để nó sẽ khác biệt ít hơn khi tôi so sánh các tệp theo dõi XML)
Phần có liên quan của kế hoạch thực hiện 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""
/>
Nếu bạn nhìn vào Bài kiểm tra số 3, thì nó đang thực hiện SELECT TOP (2) NULL
trên hệ thống "từ xa". Theo dõi SQL Profiler cho thấy kiểu dữ liệu của trường từ xa này trên thực tế INT
. Theo dõi cũng cho thấy trường ở phía máy khách (tức là nơi tôi đang chạy truy vấn từ đó) DATE
, như mong đợi. Việc chuyển đổi từ INT
sang DATE
, một cái gì đó sẽ gặp lỗi trong SQL Server, chỉ hoạt động tốt trong trình điều khiển OLEDB. Giá trị từ xa là NULL
, do đó, nó được trả về trực tiếp, do đó <ColumnReference Column="Expr1002" />
.
Nếu bạn nhìn vào Bài kiểm tra số 1, thì nó đang thực hiện SELECT 1
trên hệ thống "từ xa". Theo dõi SQL Profiler cho thấy kiểu dữ liệu của trường từ xa này trên thực tế INT
. Theo dõi cũng cho thấy trường ở phía máy khách (tức là nơi tôi đang chạy truy vấn từ đó) GUID
, như mong đợi. Việc chuyển đổi từ INT
sang GUID
(hãy nhớ, điều này được thực hiện trong trình điều khiển và OLEDB gọi đó là "GUID"), một cái gì đó sẽ gặp lỗi trong SQL Server, chỉ hoạt động tốt trong trình điều khiển OLEDB. Giá trị từ xa là không NULL
, vì vậy nó được thay thế bằng một nghĩa đen NULL
, do đó <Const ConstValue="NULL" />
.
Thử nghiệm # 2 thất bại, vì vậy không có kế hoạch thực hiện. Tuy nhiên, nó truy vấn hệ thống "từ xa" thành công, nhưng không thể trả lại tập kết quả. Truy vấn mà SQL Profiler thu được là:
SELECT TOP (2) NULL "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001"
Đó là cùng một truy vấn đang được thực hiện trong Bài kiểm tra số 1, nhưng ở đây nó không thành công. Có những khác biệt nhỏ khác, nhưng tôi không thể diễn giải đầy đủ thông tin liên lạc OLEDB. Tuy nhiên, trường từ xa vẫn hiển thị dưới dạng INT
(wType = 3 = adInteger / số nguyên có chữ ký bốn byte / DBTYPE_I4) trong khi trường "client" vẫn hiển thị dưới dạng GUID
(wType = 72 = adGUID / định danh duy nhất toàn cầu / DBTYPE_GUID). Tài liệu OLE DB không giúp ích nhiều vì Chuyển đổi loại dữ liệu GUID , Chuyển đổi loại dữ liệu DBDATE và Chuyển đổi loại dữ liệu I4 cho thấy việc chuyển đổi từ I4 sang GUID hoặc DBDATE không được hỗ trợ, nhưng DATE
truy vấn vẫn hoạt động.
Các tệp Trace XML cho ba bài kiểm tra được đặt trên PasteBin. Nếu bạn muốn xem chi tiết về nơi mỗi bài kiểm tra khác với các bài kiểm tra khác, bạn có thể lưu chúng cục bộ và sau đó thực hiện "khác biệt" với chúng. Các tập tin là:
- NullGuidSuccess.xml
- NullGuidError.xml
- NullDateSuccess.xml
LỚN?
Phải làm gì về nó? Có lẽ chỉ là phần giải quyết mà tôi đã lưu ý trong phần trên cùng, với điều kiện Máy khách bản địa SQL - SQLNCLI11
- không được dùng cho SQL Server 2012. Hầu hết các trang MSDN về chủ đề Máy khách bản địa của SQL Server đều có thông báo sau tại hàng đầu:
Cảnh báo
SQL Server Client Client (SNAC) không được hỗ trợ ngoài SQL Server 2012. Tránh sử dụng SNAC trong công việc phát triển mới và lên kế hoạch sửa đổi các ứng dụng hiện đang sử dụng nó. Các điều khiển Microsoft ODBC cho SQL Server cung cấp kết nối có nguồn gốc từ Windows sang Microsoft SQL Server và cơ sở dữ liệu Microsoft Azure SQL.
Để biết thêm thông tin, vui lòng xem:
ODBC ??
Tôi đã thiết lập Máy chủ được liên kết ODBC thông qua:
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;
Và sau đó thử:
SELECT CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
FROM [LocalODBC].[tempdb].[sys].[objects] rmt;
và nhận được lỗi sau:
Nhà cung cấp OLE DB "MSDASQL" cho máy chủ được liên kết "LocalODBC" thông báo trả về "Chuyển đổi được yêu cầu không được hỗ trợ."
Msg 7341, Cấp 16, Trạng thái 2, Dòng 53
Không thể nhận giá trị hàng hiện tại của cột "(biểu thức do người dùng tạo) .Expr1002" từ nhà cung cấp OLE DB "MSDASQL" cho máy chủ được liên kết "LocalODBC".
PS
Vì nó liên quan đến việc vận chuyển GUID giữa các máy chủ từ xa và cục bộ, các giá trị không phải NULL được xử lý thông qua một cú pháp đặc biệt. Tôi nhận thấy thông tin Sự kiện OLE DB sau trong theo dõi SQL Profiler khi tôi chạy CAST(0x00 AS UNIQUEIDENTIFIER)
:
<RemoteQuery RemoteSource="Local" RemoteQuery=
"SELECT {guid'00000000-0000-0000-0000-000000000000'} "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001""
/>
PPS
Tôi cũng đã thử nghiệm OPENQUERY
với truy vấn sau:
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;
và nó đã thành công, thậm chí không có tham chiếu đối tượng địa phương. Tệp XML theo dõi SQL Profiler đã được đăng lên PasteBin tại:
NullGuidSuccessOPENQUERY.xml
Kế hoạch thực hiện XML cho thấy nó sử dụng NULL
hằng số, giống như trong Thử nghiệm # 1.