Saya meminta data dari server yang terhubung melalui tampilan di server asal. Tampilan harus menyertakan beberapa kolom standar, seperti Created
, Modified
dan Deleted
, tetapi dalam hal ini tabel pada server sumber tidak memiliki info yang sesuai. Kolom karena itu secara eksplisit dilemparkan ke jenisnya masing-masing. Saya memperbarui tampilan, mengubah kolom dari
NULL AS Modified
untuk
CAST(NULL as DateTime) as Modified
Namun, setelah melakukan pembaruan ini, tampilan memicu pesan kesalahan berikut:
Msg 7341, Level 16, State 2, Line 3 Tidak bisa mendapatkan nilai baris saat ini dari kolom "(ekspresi yang dihasilkan pengguna) .Ex100100" dari penyedia OLE DB "SQLNCLI11" untuk server yang terhubung "".
Kami telah melakukan "pemeran eksplisit" ini - mengubah secara umum di server asal tanpa khawatir, dan saya menduga masalah ini mungkin terkait dengan versi server yang terlibat. Kami tidak benar-benar perlu menerapkan pemeran ini, tetapi rasanya lebih bersih. Saat ini saya hanya ingin tahu mengapa ini terjadi.
Versi Server (asal):
Microsoft SQL Server 2012 - 11.0.5058.0 (X64) 14 Mei 2014 18:34:29 Hak Cipta (c) Microsoft Corporation Enterprise Edition (64-bit) pada Windows NT 6.1 (Build 7601: Paket Layanan 1) (Hypervisor)
Versi Server (ditautkan):
Microsoft SQL Server 2008 R2 (SP1) - 10.50.2500.0 (X64) 17 Juni 2011 00:54:03 Hak cipta (c) Microsoft Corporation Enterprise Edition (64-bit) pada Windows NT 6.1 (Build 7601: Paket Layanan 1) (Hypervisor )
Sunting
Saya baru menyadari bahwa saya membuat kesalahan dengan tidak memposting semua kolom yang dimaksud, dan saya harus minta maaf karena meninggalkan detail penting. Saya tidak tahu bagaimana saya tidak memperhatikan ini lebih cepat. Namun pertanyaannya masih tetap.
Para pemain keliru tidak terjadi dengan para pemain untuk DateTime, tetapi dengan kolom yang dilemparkan ke UniqueIdentifier.
Inilah pelakunya:
CAST(NULL AS UniqueIdentifier) AS [GUID]
UniqueIdentifiers didukung pada SQL Server 2008 R2, dan seperti yang disebutkan dalam komentar, kueri yang dilakukan oleh tampilan berjalan dengan baik di server yang ditautkan.
Danish_Norwegian_CI_AS
dan server tertaut memiliki collationSQL_Danish_Pref_CP1_CI_AS
, tetapiCOLLATE
klausa tidak dapat diterapkan keDateTime
kolom, jadi saya tidak mendapatkan lebih jauh!select Null from ...
dalam DENGAN atau permintaan bersarang dan yangCAST
lain?INT
Anda telah mengubah datatype dengan melakukannya. Saya tidak tahu mengapa itu akan memberi Anda pesan kesalahan itu.Jawaban:
Jadi, saya bisa mereproduksi kesalahan setelah menyadari bahwa
CAST
itu dilakukan secara lokal, bukan pada contoh jarak jauh. Saya sebelumnya merekomendasikan pindah ke SP3 dengan harapan memperbaiki ini (sebagian karena tidak dapat mereproduksi kesalahan pada SP3, dan sebagian karena itu menjadi ide yang bagus terlepas). Namun, sekarang saya dapat mereproduksi kesalahan, jelas bahwa pindah ke SP3, sementara masih mungkin ide yang baik, tidak akan memperbaikinya. Dan saya juga mereproduksi kesalahan dalam SQL Server 2008 R2 RTM dan 2014 SP1 (menggunakan "loop-back" Server Linked lokal dalam ketiga kasus).Tampaknya masalah ini berkaitan dengan di mana kueri mengeksekusi, atau setidaknya di mana sebagian dari itu mengeksekusi. Saya mengatakan ini karena saya bisa mendapatkan
CAST
operasi untuk bekerja, tetapi hanya dengan memasukkan referensi ke objek DB lokal:Itu benar-benar berfungsi. Tetapi yang berikut mendapatkan kesalahan asli:
Saya menduga bahwa ketika tidak ada referensi lokal, seluruh permintaan dikirim ke sistem jarak jauh untuk dieksekusi, dan untuk beberapa alasan
NULL
s tidak dapat dikonversi keUNIQUEIDENTIFIER
, atau mungkinNULL
diterjemahkan oleh driver OLE DB salah.Berdasarkan pengujian yang telah saya lakukan, ini akan muncul sebagai bug, tapi saya tidak yakin apakah bug itu ada di dalam SQL Server atau driver SQL Server Native Client / OLEDB. Namun, kesalahan konversi terjadi dalam pengandar OLEDB, dan karena itu belum tentu masalah konversi dari
INT
keUNIQUEIDENTIFIER
(konversi yang tidak diizinkan dalam SQL Server) karena pengandar tidak menggunakan SQL Server untuk melakukan konversi (SQL Server juga tidak memungkinkan untuk mengkonversiINT
keDATE
, namun pegangan sopir OLEDB yang berhasil, seperti yang ditunjukkan dalam salah satu tes).Saya menjalankan tiga tes. Untuk dua yang berhasil, saya melihat rencana eksekusi XML yang menunjukkan permintaan yang sedang dijalankan dari jarak jauh. Untuk ketiganya, saya menangkap Pengecualian atau peristiwa OLEDB melalui SQL Profiler:
Acara:
Filter Kolom:
UJI
Tes 1
CAST(NULL AS UNIQUEIDENTIFIER)
itu bekerjaBagian yang relevan dari rencana eksekusi XML:
Tes 2
CAST(NULL AS UNIQUEIDENTIFIER)
itu gagal(catatan: Saya menyimpan subquery di sana, berkomentar, sehingga akan ada satu perbedaan kurang ketika saya membandingkan file jejak XML)
Tes 3
CAST(NULL AS DATE)
itu bekerja(catatan: Saya menyimpan subquery di sana, berkomentar, sehingga akan ada satu perbedaan kurang ketika saya membandingkan file jejak XML)
Bagian yang relevan dari rencana eksekusi XML:
Jika Anda melihat Tes # 3, itu sedang melakukan
SELECT TOP (2) NULL
pada sistem "remote". Jejak SQL Profiler menunjukkan bahwa tipe data dari bidang jauh ini sebenarnyaINT
. Jejak juga menunjukkan bahwa bidang di sisi klien (yaitu tempat saya menjalankan kueri dari)DATE
, seperti yang diharapkan. Konversi dariINT
keDATE
, sesuatu yang akan mendapatkan kesalahan dalam SQL Server, berfungsi dengan baik dalam driver OLEDB. Nilai jarak jauh adalahNULL
, sehingga dikembalikan secara langsung, karenanya<ColumnReference Column="Expr1002" />
.Jika Anda melihat Tes # 1, itu sedang melakukan
SELECT 1
pada sistem "remote". Jejak SQL Profiler menunjukkan bahwa tipe data dari bidang jauh ini sebenarnyaINT
. Jejak juga menunjukkan bahwa bidang di sisi klien (yaitu tempat saya menjalankan kueri dari)GUID
, seperti yang diharapkan. Konversi dariINT
keGUID
(ingat, ini dilakukan di dalam driver, dan OLEDB menyebutnya "GUID"), sesuatu yang akan mendapatkan kesalahan dalam SQL Server, berfungsi dengan baik di dalam driver OLEDB. Nilai jarak jauh tidakNULL
, sehingga diganti dengan literalNULL
, karenanya<Const ConstValue="NULL" />
.Tes # 2 gagal, jadi tidak ada rencana eksekusi. Namun, ia berhasil meng-query sistem "remote", tetapi tidak bisa mengembalikan set hasil. Kueri yang ditangkap SQL Profiler adalah:
Itu adalah permintaan yang sama persis yang sedang dilakukan di Tes # 1, namun di sini gagal. Ada perbedaan kecil lainnya, tetapi saya tidak dapat sepenuhnya menafsirkan komunikasi OLEDB. Namun, bidang jarak jauh masih ditampilkan sebagai
INT
(wType = 3 = adInteger / integer bertanda empat-byte / DBTYPE_I4) sementara bidang "klien" masih ditampilkan sebagaiGUID
(wType = 72 = adGUID / pengidentifikasi unik global / DBTYPE_GUID). Dokumentasi OLE DB tidak banyak membantu karena Konversi Tipe Data GUID , Konversi Tipe Data DBDATE , dan Konversi Tipe Data I4 menunjukkan bahwa konversi dari I4 ke GUID atau DBDATE tidak didukung, namunDATE
kueri berfungsi.File Trace XML untuk tiga tes terletak di PasteBin. Jika Anda ingin melihat detail di mana masing-masing tes berbeda dari yang lain, Anda dapat menyimpannya secara lokal dan kemudian melakukan "perbedaan" pada mereka. File-file tersebut adalah:
JADI?
Apa yang harus dilakukan tentang hal itu? Mungkin hanya pekerjaan-sekitar yang saya catat di bagian atas, mengingat bahwa SQL Native Client -
SQLNCLI11
- sudah usang pada SQL Server 2012. Sebagian besar halaman MSDN tentang topik SQL Server Native Client memiliki pemberitahuan berikut di teratas:Untuk info lebih lanjut, silakan lihat:
ODBC ??
Saya mengatur ODBC Linked Server melalui:
Dan kemudian mencoba:
dan menerima kesalahan berikut:
PS
Karena terkait dengan pengangkutan GUID antara server jauh dan lokal, nilai-nilai non-NULL ditangani melalui sintaks khusus. Saya perhatikan info acara OLE DB berikut di jejak SQL Profiler ketika saya berlari
CAST(0x00 AS UNIQUEIDENTIFIER)
:PPS
Saya juga menguji melalui
OPENQUERY
dengan permintaan berikut:dan itu berhasil, bahkan tanpa referensi objek lokal. File XML jejak SQL Profiler telah diposting ke PasteBin di:
NullGuidSuccessOPENQUERY.xml
Paket eksekusi XML memperlihatkannya menggunakan
NULL
konstanta, sama seperti pada Uji # 1.sumber
Hanya ada solusi buruk - gunakan beberapa tanggal konstan seperti
'1900-01-01'
bukannull
.Setelah impor Anda dapat memperbarui kolom dengan
1900-01-01
kembali ke Null.Ini adalah semacam fitur / bug SQL 2012 sesuai di sini .
Sunting: diganti
1900-00-00
dengan tanggal yang valid1900-01-01
sesuai @a_horse_with_no_name komentar di bawah ini.sumber
uniqueidentifier
kolom. Atau mungkin itu bisa diadaptasi - sesuatu sepertiCAST('00000000-0000-0000-0000-000000000000' AS UniqueIdentifier) AS [GUID]
, mungkin?1900-00-00
adalah tanggal yang tidak valid dan tidak akan diterima.Masalah ini terkait dengan konversi tipe data (seperti yang ditampilkan di komentar).
Pertimbangkan yang berikut ini:
Perhatikan bahwa tipe
NullColumn
isint
. SQL Server tidak suka mengonversiint
nilai menjadiuniqueidentifier
.SELECT
Pernyataan ini akan gagal pada konversi tipe data:Sementara nilai spesifik ini (NULL) dapat dilemparkan ke GUID, SQL Server melempar kesalahan berdasarkan konversi tipe data, bahkan sebelum melihat nilai-nilai spesifik. Sebagai gantinya, Anda perlu melakukan operasi multi-langkah
CAST
untuk mengubah implisitint
ke tipe data yang dapat dikonversi secara bersih menjadiuniqueidentifer
- yang berarti melakukan casting terlebih dahuluvarchar
kemudian keuniqueidentifier
:sumber
OP akhirnya dapat memutuskan apakah ini merupakan jawaban yang tepat.
Saya tidak punya bukti 'absolut', tapi saya 'curiga' masalahnya berasal dari kenyataan bahwa UniqueIdentifer tergantung pada server dan mungkin penyedia mengalami kesulitan mencari tahu dari server mana (lokal atau jarak jauh) untuk mendapatkan pengenal unik ini, meskipun itu batal. Itu sebabnya Anda mungkin bisa membuang datatype lain dengan sukses dalam skenario ini, tetapi tidak pengidentifikasi unik. Tipe data yang bergantung pada 'server' seperti UNIQUEIDENTIFIER dan DATETIMEOFFSET akan memberi Anda kesalahan yang Anda temui.
Menggunakan OPENQUERY sebagai ganti karya 4 bagian.
sumber
Uniqueidentifier
danDateTimeOffset
menjadi server-dependent? Apakah Anda punya sumber untuk ini?Penanganan Masalah: Jawaban yang diterima tampaknya menunjukkan bahwa konversi perlu dilakukan secara lokal karena driver OLEDB tidak mendukungnya.
Jadi saya pikir solusi sederhana (setidaknya dalam kasus permintaan saya yang memilih nol
uniqueidentifier
dalam kasus dasar CTE rekursif) adalah dengan mendeklarasikan variabel nol:sumber