เหตุใดการส่งข้อมูลที่ชัดเจนนี้ทำให้เกิดปัญหากับเซิร์ฟเวอร์ที่เชื่อมโยงเท่านั้น


21

ฉันกำลังสืบค้นข้อมูลจากเซิร์ฟเวอร์ที่เชื่อมโยงผ่านมุมมองบนเซิร์ฟเวอร์ต้นทาง มุมมองต้องรวมคอลัมน์มาตรฐานสองสามมาตรฐานเช่น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 รุ่นองค์กร (64 บิต) บน Windows NT 6.1 (รุ่น 7601: Service Pack 1) (Hypervisor)

รุ่นเซิร์ฟเวอร์ (ลิงก์):

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: Service Pack 1) (Hypervisor )

แก้ไข
ฉันเพิ่งรู้ว่าฉันทำผิดพลาดโดยไม่โพสต์คอลัมน์ทั้งหมดที่เป็นปัญหาและฉันต้องขออภัยในการละทิ้งรายละเอียดที่สำคัญ ฉันไม่รู้ว่าฉันไม่สังเกตเห็นสิ่งนี้ได้เร็วกว่านี้ คำถามยังคงอยู่แม้ว่า

การโยนที่ผิดพลาดไม่ได้เกิดขึ้นกับการส่งไปยัง DateTime แต่ด้วยคอลัมน์ที่กำลังส่งไปยัง UniqueIdentifier

นี่คือผู้ร้าย:

CAST(NULL AS UniqueIdentifier) AS [GUID]

UniqueIdentifiers ได้รับการสนับสนุนบน SQL Server 2008 R2 และตามที่ระบุไว้ในความคิดเห็นแบบสอบถามที่ดำเนินการโดยมุมมองจะทำงานได้ดีบนเซิร์ฟเวอร์ที่เชื่อมโยง


คุณมีการตั้งค่า ANSI NULL ที่แตกต่างกันในแต่ละเซิร์ฟเวอร์หรือไม่ การเปรียบเทียบที่แตกต่างกันอย่างไร
Randolph West

เซิร์ฟเวอร์ทั้งสองมี ANSI NULL = 0 เซิร์ฟเวอร์ต้นทางมีการเปรียบเทียบDanish_Norwegian_CI_ASและเซิร์ฟเวอร์ที่เชื่อมโยงมีการเปรียบเทียบSQL_Danish_Pref_CP1_CI_ASแต่COLLATEข้อไม่สามารถใช้กับDateTimeคอลัมน์ดังนั้นฉันจึงไม่ได้ไปไกลกว่านี้มาก!
krystah

สิ่งนี้จะล้มเหลวหรือไม่หากมีselect Null from ...ใน With หรือซ้อนกันแบบสอบถามและCASTอื่น ๆ ?
Stoleg

หากไม่มีการส่งที่ชัดเจนมันจะได้รับการปฏิบัติเช่นเดียวกับที่INTคุณเปลี่ยนประเภทข้อมูลโดยการทำเช่นนั้น ฉันไม่รู้ว่าทำไมถึงทำให้ข้อความแสดงข้อผิดพลาดนั้นถึงคุณ
Martin Smith

ก่อนหน้านี้ฉันได้พยายามห่อค่าที่เลือกด้วยค่าจริงใน CTE จากนั้นเลือกค่าเหล่านั้นและตรึงค่า NULL แบบ casted ในคำสั่งที่ตามหลัง CTE โดยไม่มีโชค ฉันลองข้อเสนอแนะของคุณรักษา NULLs ใน CTE และส่งไปยังคำสั่งที่สอบถาม CTE แต่ก็ให้ข้อผิดพลาดเดียวกัน
krystah

คำตอบ:


13

ดังนั้นฉันสามารถทำซ้ำข้อผิดพลาดหลังจากทราบว่าCASTกำลังทำในเครื่องไม่ใช่ในอินสแตนซ์ระยะไกล ก่อนหน้านี้ฉันแนะนำให้เลื่อนไปที่ SP3 โดยหวังว่าจะแก้ไขปัญหานี้ (บางส่วนเนื่องจากไม่สามารถทำซ้ำข้อผิดพลาดใน SP3 และบางส่วนเนื่องจากเป็นความคิดที่ดีโดยไม่คำนึงถึง) อย่างไรก็ตามตอนนี้ฉันสามารถทำซ้ำข้อผิดพลาดได้ชัดเจนว่าการย้ายขึ้นไปที่ SP3 ในขณะที่ยังคงเป็นความคิดที่ดีจะไม่สามารถแก้ไขปัญหานี้ได้ และฉันยังทำซ้ำข้อผิดพลาดใน SQL Server 2008 R2 RTM และ 2014 SP1 (โดยใช้เซิร์ฟเวอร์ที่เชื่อมโยงแบบ "วนกลับ" ในทั้งสามกรณี)

ดูเหมือนว่าปัญหานี้จะทำอย่างไรกับที่แบบสอบถามจะดำเนินการหรืออย่างน้อยที่เป็นส่วนหนึ่ง (s)ของมันกำลังดำเนินการ ฉันพูดแบบนี้เพราะฉันสามารถทำให้CASTการทำงานทำงานได้ แต่โดยรวมถึงการอ้างอิงไปยังวัตถุฐานข้อมูลท้องถิ่น:

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หรืออาจNULLเป็นการแปลโดยไดรเวอร์ OLE DB อย่างไม่ถูกต้อง


จากการทดสอบที่ฉันทำไปแล้วดูเหมือนว่าจะเป็นข้อผิดพลาด แต่ฉันไม่แน่ใจว่าข้อผิดพลาดนั้นอยู่ใน SQL Server หรือไดรเวอร์ SQL Server Native Client / OLEDB อย่างไรก็ตามข้อผิดพลาดในการแปลงเกิดขึ้นภายในไดรเวอร์ OLEDB และดังนั้นจึงไม่จำเป็นต้องมีปัญหาในการแปลงจากINTเป็นUNIQUEIDENTIFIER(การแปลงที่ไม่ได้รับอนุญาตใน SQL Server) เนื่องจากไดรเวอร์ไม่ได้ใช้ SQL Server เพื่อทำการแปลง (SQL Server ยังไม่ อนุญาตให้แปลงINTเป็นDATEแต่ไดรเวอร์ OLEDB จัดการได้สำเร็จดังที่แสดงในการทดสอบอย่างใดอย่างหนึ่ง)

ฉันทำการทดสอบสามครั้ง สำหรับทั้งสองที่ประสบความสำเร็จฉันดูแผนการดำเนินการ XML ซึ่งแสดงแบบสอบถามที่กำลังดำเนินการจากระยะไกล สำหรับทั้งสามฉันจับข้อยกเว้นหรือเหตุการณ์ OLEDB ผ่าน SQL Profiler:

กิจกรรม:

  • ข้อผิดพลาดและคำเตือน
    • ความสนใจ
    • ข้อยกเว้น
    • คำเตือนการดำเนินการ
    • ข้อความแสดงความผิดพลาดของผู้ใช้
  • OLEDB
    • ทั้งหมด
  • TSQL
    • ทั้งหมดยกเว้น :
      • SQL: StmtRecompile
      • XQuery ประเภทคงที่

ตัวกรองคอลัมน์:

  • โปรแกรมประยุกต์
    • ไม่ชอบ% 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 &quot;TEMPTEST&quot;.&quot;sys&quot;.&quot;objects&quot; &quot;Tbl1001&quot;"
     />
  • ทดสอบ 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]
             --  , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
    FROM [Local].[TEMPTEST].[sys].[objects] rmt;

    (หมายเหตุ: ฉันเก็บแบบสอบถามย่อยไว้ที่นั่นใส่เครื่องหมายคอมเม้นต์เพื่อให้มันแตกต่างกันเล็กน้อยเมื่อฉันเปรียบเทียบไฟล์ติดตาม XML)

    ส่วนที่เกี่ยวข้องของแผนการดำเนินการ XML:

              <DefinedValue>
                <ColumnReference Column="Expr1002" />
                <ScalarOperator ScalarString="[Expr1002]">
                  <Identifier>
                    <ColumnReference Column="Expr1002" />
                  </Identifier>
                </ScalarOperator>
              </DefinedValue>
     ...
    <RemoteQuery RemoteSource="Local" RemoteQuery=
     "SELECT TOP (2) NULL &quot;Expr1002&quot; FROM &quot;TEMPTEST&quot;.&quot;sys&quot;.&quot;objects&quot; &quot;Tbl1001&quot;" 
     />

ถ้าคุณดูที่การทดสอบ # 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 คือ:

SELECT TOP (2) NULL "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001"

นั่นคือแบบสอบถามเดียวกันที่ทำใน Test # 1 แต่ที่นี่มันล้มเหลว มีความแตกต่างเล็กน้อยอื่น ๆ แต่ฉันไม่สามารถตีความการสื่อสาร OLEDB ได้อย่างสมบูรณ์ อย่างไรก็ตามฟิลด์ระยะไกลยังคงแสดงเป็นINT(จำนวนเต็ม wType = 3 = adInteger / สี่ไบต์ลงนาม / DBTYPE_I4) ในขณะที่ฟิลด์ "ลูกค้า" ยังคงแสดงเป็นGUID(wType = 72 = adGUID / ตัวระบุที่ไม่ซ้ำกันทั่วโลก / DBTYPE_GUID) เอกสาร OLE DB ไม่ได้ช่วยมากเป็นประเภท GUID ข้อมูลการแปลง , DBDATE ชนิดข้อมูลการแปลงและI4 ชนิดข้อมูล Conversion ที่แสดงให้เห็นว่าการแปลงจากI4ทั้งGUIDหรือDBDATEได้รับการสนับสนุนยังDATEงานแบบสอบถาม

ไฟล์ Trace XML สำหรับการทดสอบทั้งสามนั้นอยู่ใน PasteBin หากคุณต้องการดูรายละเอียดว่าแต่ละการทดสอบนั้นแตกต่างจากที่อื่นหรือไม่คุณสามารถบันทึกไว้ในเครื่องแล้วทำ "diff" ไฟล์คือ:

  1. NullGuidSuccess.xml
  2. NullGuidError.xml
  3. NullDateSuccess.xml

ERGO?

จะทำอย่างไรกับมัน? อาจเป็นเพียงแค่การแก้ไขปัญหาที่ฉันระบุไว้ในส่วนบนที่ระบุว่า SQL Native Client - SQLNCLI11- ถูกคัดค้าน ณ SQL Server 2012 หน้า MSDN ส่วนใหญ่ในหัวข้อของ SQL Server Native Client มีการแจ้งเตือนดังต่อไปนี้ที่ tOP:

การเตือน

SQL Server Native Client (SNAC) ไม่รองรับเกินกว่า SQL Server 2012 หลีกเลี่ยงการใช้ SNAC ในงานพัฒนาใหม่และวางแผนที่จะปรับเปลี่ยนแอปพลิเคชันที่ใช้งานอยู่ในปัจจุบัน Microsoft โปรแกรมควบคุม ODBC สำหรับ SQL Serverให้การเชื่อมต่อพื้นเมืองจาก Windows ไป Microsoft SQL Server และฐานข้อมูล Microsoft SQL Azure

สำหรับข้อมูลเพิ่มเติมโปรดดู:


ODBC

ฉันตั้งค่าเซิร์ฟเวอร์ที่เชื่อมโยง 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 "MSDASQL" สำหรับเซิร์ฟเวอร์ที่เชื่อมโยง "LocalODBC" ข้อความที่ส่งคืน "ไม่รองรับการแปลงที่ร้องขอ"
ข่าวสารเกี่ยวกับ 7341 ระดับ 16 สถานะ 2 บรรทัด 53
ไม่สามารถรับค่าแถวปัจจุบันของคอลัมน์ "(นิพจน์ที่ผู้ใช้สร้างขึ้น). Expr1002" จากผู้ให้บริการ OLE DB "MSDASQL" สำหรับเซิร์ฟเวอร์ที่เชื่อมโยง "LocalODBC"


PS

เนื่องจากเกี่ยวข้องกับการขนส่ง GUID ระหว่างเซิร์ฟเวอร์ระยะไกลและเซิร์ฟเวอร์ท้องถิ่นค่าที่ไม่ใช่ NULL จะถูกจัดการผ่านทางไวยากรณ์พิเศษ ฉันสังเกตเห็นข้อมูล OLE DB Event ต่อไปนี้ในการติดตาม SQL Profiler เมื่อฉันวิ่งCAST(0x00 AS UNIQUEIDENTIFIER):

<RemoteQuery RemoteSource="Local" RemoteQuery=
 "SELECT {guid'00000000-0000-0000-0000-000000000000'} &quot;Expr1002&quot; FROM &quot;TEMPTEST&quot;.&quot;sys&quot;.&quot;objects&quot; &quot;Tbl1001&quot;" 
 />

PPS

ฉันยังทดสอบผ่านทาง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;

และมันก็ประสบความสำเร็จแม้ว่าจะไม่มีการอ้างอิงวัตถุท้องถิ่น ไฟล์ XML การติดตามของผู้สร้างโปรไฟล์ SQL ได้รับการโพสต์ไปยัง PasteBin ที่:

NullGuidSuccessOPENQUERY.xml

แผนการดำเนินการ XML แสดงโดยใช้NULLค่าคงที่เช่นเดียวกับใน Test # 1


ฉันได้สร้างปัญหานี้ขึ้นใหม่ในปี 2012 sp3-cu1
Bob Klimes

@ BobKlimes ที่น่าสนใจ นั่นคือการใช้เซิร์ฟเวอร์ที่เชื่อมโยงกับอินสแตนซ์ 2008 R2 หรือลูปแบ็คหรือไม่
โซโลมอน Rutzky

เซิร์ฟเวอร์ที่เชื่อมโยงระยะไกลคือ 2008 R2 sp2 + MS15-058 (10.50.4339.0)
Bob Klimes

1
ดูเหมือนจะไม่เกี่ยวข้องกับรุ่น มีการทดสอบคอมโบหลายชุดของปี 2008r2,2012,2014,2016 และมีข้อผิดพลาดในการผลิตจนถึงปี 2008r2-2008r2
Bob Klimes

2
ช่างเป็นปัญหาที่คลุมเครือเหลือเกิน ขอบคุณมากสำหรับความเข้าใจและการวิจัย @srutzky มันเป็นที่นิยมอย่างมาก ฉันจะจำความเสื่อมของ SNAC ไว้ในใจสำหรับการทำงานในอนาคตและสำรองทางแก้ปัญหาดังกล่าวข้างต้น การทำงานที่ดี!
krystah

4

มีเพียงการแก้ปัญหาที่น่าเกลียดคือ - ใช้อย่างต่อเนื่องวันที่บางคนชอบแทน'1900-01-01'null

CAST('1900-01-01' as DateTime) as Modified

หลังจากนำเข้าคุณสามารถอัปเดตคอลัมน์โดย1900-01-01กลับไปที่ Null

นี้เป็นชนิดของ SQL คุณลักษณะ 2012 / ข้อผิดพลาดตามที่นี่

แก้ไข:แทนที่1900-00-00ด้วยวันที่ที่ถูกต้อง1900-01-01ตามความคิดเห็น @a_horse_with_no_name ด้านล่าง


วิธีแก้ปัญหานี้อาจจะคุ้มค่าที่จะกล่าวถึง แต่อาจไม่เกี่ยวข้องอีกต่อไปในขณะนี้ที่ OP ได้ชี้แจงว่าผู้กระทำผิดของปัญหาคือuniqueidentifierคอลัมน์ หรืออาจจะดัดแปลงCAST('00000000-0000-0000-0000-000000000000' AS UniqueIdentifier) AS [GUID]ก็ได้
Andriy M

ขอบคุณเพื่อน. กำลังส่งไปยัง GUID ที่ว่างเปล่าหรือ DateTime แต่ฉันต้องเข้าใจว่าทำไมสิ่งนี้จึงเกิดขึ้น นอกจากนี้ยังเป็นมูลค่าการกล่าวขวัญว่าฉันไม่ได้นำเข้าอะไรดังนั้นจึงไม่มีความเป็นไปได้ที่จะแก้ไขข้อมูลต้นฉบับ
krystah

1
1900-00-00เป็นวันที่ไม่ถูกต้องและจะไม่ได้รับการยอมรับ
a_horse_with_no_name

@a_horse_with_no_name: ความผิดพลาดโง่ ๆ คงที่
Anton Krouglov

2

ปัญหาเกี่ยวข้องกับการแปลงประเภทข้อมูล (ตามที่เห็นในความคิดเห็น)

พิจารณาสิ่งต่อไปนี้:

SELECT NULL as NullColumn INTO SomeTable;
EXEC sp_help SomeTable;
DROP TABLE SomeTable;

โปรดทราบว่าเป็นประเภทNullColumn intSQL Server ไม่ชอบการแปลงค่าint คำสั่งuniqueidentifierนี้SELECTจะล้มเหลวในการแปลงประเภทข้อมูล:

--Just a SELECT from nothing
SELECT CAST(CAST(NULL as int) as uniqueidentifier);
--
--or to see it from a physical table:
SELECT NULL as NullColumn INTO SomeTable;
SELECT CAST(NullColumn as uniqueidentifier) FROM SomeTable;
DROP TABLE SomeTable;

ข่าวสารเกี่ยวกับ 529 ระดับ 16 สถานะ 2 บรรทัด 3

ไม่อนุญาตการแปลงที่ชัดเจนจากประเภทข้อมูล int ไปเป็น Uniqueidentifier

ในขณะที่ค่าเฉพาะนี้ (NULL) สามารถส่งไปยัง GUID ได้ แต่ SQL Server จะโยนข้อผิดพลาดตามการแปลงชนิดข้อมูลก่อนที่จะดูค่าเฉพาะ แต่คุณจะต้องดำเนินการหลายขั้นตอนCASTเพื่อเปลี่ยนนัยintไปเป็นประเภทข้อมูลที่สามารถแปลงอย่างหมดจดเป็น - uniqueidentiferซึ่งหมายถึงการคัดเลือกก่อนvarcharจากนั้นเป็นuniqueidentifier:

--Just a SELECT from nothing
SELECT CAST(CAST(CAST(NULL as int) as varchar) as uniqueidentifier);
--
--or to see it from a physical table:
SELECT NULL as NullColumn INTO SomeTable;
SELECT CAST(CAST(NullColumn as varchar(32)) as uniqueidentifier) FROM SomeTable;
DROP TABLE SomeTable;

ปัญหานี้ไม่ได้เกิดจากการแปลงประเภทข้อมูลอย่างน้อยไม่อยู่ใน SQL Server รายละเอียดอยู่ในคำตอบของฉันแต่การแปลงจะดำเนินการภายในไดรเวอร์ OLEDB ไม่ใช่ใน SQL Server และกฎการแปลงไม่เหมือนกัน
โซโลมอน Rutzky

1

ในที่สุด OP สามารถตัดสินใจได้ว่านี่เป็นคำตอบที่เหมาะสมหรือไม่

ฉันไม่มีข้อพิสูจน์ 'แน่นอน' แต่ฉันสงสัยว่าปัญหาเกิดขึ้นจากความจริงที่ว่า UniqueIdentifer ขึ้นอยู่กับเซิร์ฟเวอร์และบางทีผู้ให้บริการอาจมีปัญหาในการหาเซิร์ฟเวอร์ตัวใดตัวหนึ่ง โมฆะ นั่นเป็นเหตุผลว่าทำไมคุณสามารถส่งประเภทข้อมูลอื่น ๆ ได้สำเร็จในสถานการณ์นี้ แต่ไม่ใช่ตัวระบุที่ไม่ซ้ำ ชนิดข้อมูลที่ขึ้นอยู่กับ 'เซิร์ฟเวอร์' เช่น UNIQUEIDENTIFIERS และ DATETIMEOFFSET จะทำให้คุณเกิดข้อผิดพลาด

ใช้ OPENQUERY แทนการใช้ชื่อ 4 ส่วน

set nocount on  
DECLARE @cmd nVARCHAR(max)
DECLARE @datatype SYSNAME

DECLARE _CURSOR CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY
FOR
SELECT NAME
FROM sys.types 

OPEN _CURSOR

FETCH NEXT
FROM _CURSOR
INTO @datatype

WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY
        SET @cmd = 'select top 1 cast(null as ' + @Datatype + ') as CastedData from remoteserver.remotedatabase.remoteschema.remotetable'
        PRINT @cmd
        EXECUTE sp_executesql @cmd
    END TRY

    BEGIN CATCH
        PRINT Error_message()
    END CATCH

FETCH NEXT
FROM _CURSOR
INTO @datatype
END --End While

CLOSE _CURSOR

DEALLOCATE _CURSOR

คุณหมายถึงอะไรUniqueidentifierและDateTimeOffsetขึ้นอยู่กับเซิร์ฟเวอร์? คุณมีแหล่งที่มาสำหรับสิ่งนี้หรือไม่?
krystah

@krystah - จากลิงค์นี้ ( technet.microsoft.com/en-us/library/ms190215(v=sql.105).aspx ) "ประเภทข้อมูลที่ไม่ซ้ำกันเก็บค่าไบนารี่ 16 ไบต์ที่ทำงานเป็นตัวระบุที่ไม่ซ้ำกันทั่วโลก (GUID) . GUID เป็นเลขฐานสองที่ไม่ซ้ำใครไม่มีคอมพิวเตอร์เครื่องอื่นในโลกที่จะสร้างค่าซ้ำของ GUID นั้นการใช้หลักสำหรับ GUID นั้นสำหรับการกำหนดตัวระบุที่จะต้องไม่ซ้ำกันในเครือข่ายที่มีคอมพิวเตอร์จำนวนมากในหลาย ๆ ไซต์ "
Scott Hodgin

สำหรับ DateTimeOffSet ( msdn.microsoft.com/en-us/library/bb630289.aspx ) กำหนดวันที่ที่รวมกับเวลาของวันที่มีการรับรู้เขตเวลาและยึดตามนาฬิกา 24 ชั่วโมง
Scott Hodgin

ฉัน 'อนุมาน' ว่าเนื่องจากประเภทข้อมูลทั้งสองนี้ดูเหมือนว่าจะเป็นประเภทเดียวที่ให้ข้อผิดพลาดในสถานการณ์ของคุณและชนิดข้อมูลเหล่านั้นเป็น 'เซิร์ฟเวอร์ขึ้นอยู่กับ' นั่นคือเหตุผลสำหรับปัญหาของคุณ หากคุณใช้ OPENQUERY เพื่อดึงผลลัพธ์ของคุณจากมุมมองของคุณและเพิ่มค่าว่างที่เพิ่มขึ้นมันน่าจะทำงานได้เพราะผู้ให้บริการรู้ 'ที่' เพื่อรับข้อมูล
Scott Hodgin

@krystah และ Scott: ประเภทข้อมูลทั้งสองนี้ไม่ได้ขึ้นอยู่กับเซิร์ฟเวอร์อย่างน้อยก็ไม่ใช่วิธีที่คุณอธิบายและบอกนัย GUID เป็น "สถาปัตยกรรม" ที่ต้องพึ่งพาในแง่ของการแสดงไบนารีพื้นฐาน (ดูที่นี่สำหรับรายละเอียด) แต่ถ้านั่นเป็นปัญหาที่นี่แล้วจะไม่มี GUID ใดที่ถ่ายโอนอย่างถูกต้อง สำหรับ DATETIMEOFFSET นั้นจะรู้ได้ว่าออฟเซ็ตไม่ใช่โซนเวลา / TimeZoneID จริง ในขณะที่ทั้งคู่ใช้ข้อมูลระบบเพื่อสร้างค่าใหม่ไม่มีการสร้างค่าใหม่ที่นี่และหากเป็นเช่นนั้นพวกเขาจะไม่ถูกสร้างขึ้นในผู้ให้บริการ
โซโลมอน Rutzky

0

วิธีแก้ปัญหา: คำตอบที่ยอมรับดูเหมือนจะบ่งบอกว่าการแปลงต้องเกิดขึ้นในพื้นที่เพราะไดรเวอร์ OLEDB ไม่รองรับ

ดังนั้นฉันคิดว่าวิธีแก้ปัญหาง่าย ๆ (อย่างน้อยในกรณีของแบบสอบถามของฉันซึ่งเลือก null uniqueidentifierในกรณีพื้นฐานของ recursive CTE) คือการประกาศตัวแปรว่าง:

declare @nullGuid as uniqueidentifier = null;

--Instead of...
CAST(NULL AS UniqueIdentifier) AS [GUID]

--use
@nullGuid AS [GUID]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.