จากเอกสาร :
ตั้งค่าลักษณะการทำงานของฐานข้อมูลบางอย่างให้เข้ากันได้กับ SQL Server รุ่นที่ระบุ
...
ระดับความเข้ากันได้ให้ความเข้ากันได้แบบย้อนหลังบางส่วนเท่านั้นกับ SQL Server รุ่นก่อนหน้า ใช้ระดับความเข้ากันได้เป็นเครื่องมือช่วยในการโยกย้ายระหว่างกาลเพื่อแก้ไขความแตกต่างของรุ่นในพฤติกรรมที่ควบคุมโดยการตั้งค่าระดับความเข้ากันได้ที่เกี่ยวข้อง
ในการตีความของฉันโหมดความเข้ากันได้เป็นเรื่องเกี่ยวกับพฤติกรรมและการแยกไวยากรณ์ไม่ใช่สำหรับสิ่งที่โปรแกรมแยกวิเคราะห์พูดว่า "เฮ้คุณไม่สามารถใช้ROW_NUMBER()
!" บางครั้งระดับความเข้ากันได้ที่ต่ำกว่าจะทำให้คุณไม่สามารถใช้งานไวยากรณ์ต่อไปได้อีกต่อไปและบางครั้งก็ป้องกันไม่ให้คุณใช้โครงสร้างไวยากรณ์ใหม่ เอกสารประกอบแสดงตัวอย่างที่ชัดเจนหลายประการ แต่นี่คือตัวอย่างบางส่วน:
ผ่านฟังก์ชั่นในตัวเป็นฟังก์ชั่นข้อโต้แย้ง
รหัสนี้ใช้งานได้ในระดับความเข้ากันได้ 90+:
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL);
แต่ใน 80 มันให้:
ข่าวสารเกี่ยวกับ 102 ระดับ 15 สถานะ 1
ไวยากรณ์ไม่ถูกต้องใกล้กับ '('
ปัญหาเฉพาะที่นี่คือใน 80 คุณไม่ได้รับอนุญาตให้ผ่านฟังก์ชั่นที่มีอยู่ในฟังก์ชั่น หากคุณต้องการอยู่ในโหมดเข้ากันได้ 80 โหมดคุณสามารถแก้ไขได้โดยพูดว่า:
DECLARE @db_id INT = DB_ID();
SELECT *
FROM sys.dm_db_index_physical_stats(@db_id, NULL, NULL, NULL, NULL);
การส่งประเภทตารางไปยังฟังก์ชันที่ให้คุณค่ากับตาราง
คุณสามารถรับข้อผิดพลาดทางไวยากรณ์เมื่อใช้ TVP และพยายามส่งผ่านไปยังฟังก์ชันที่มีค่าเป็นตาราง ใช้งานได้ในระดับความเข้ากันได้ที่ทันสมัย:
CREATE TYPE dbo.foo AS TABLE(bar INT);
GO
CREATE FUNCTION dbo.whatever
(
@foo dbo.foo READONLY
)
RETURNS TABLE
AS
RETURN (SELECT bar FROM @foo);
GO
DECLARE @foo dbo.foo;
INSERT @foo(bar) SELECT 1;
SELECT * FROM dbo.whatever(@foo);
อย่างไรก็ตามเปลี่ยนระดับความเข้ากันได้เป็น 80 และเรียกใช้สามบรรทัดสุดท้ายอีกครั้ง คุณได้รับข้อความแสดงข้อผิดพลาดนี้:
ข่าวสารเกี่ยวกับ 137, ระดับ 16, สถานะ 1, บรรทัด 19
ต้องประกาศตัวแปรสเกลาร์ "@foo"
ไม่ได้มีวิธีแก้ปัญหาใด ๆ ที่ดีจากส่วนบนของหัวของฉันนอกเหนือจากการอัพเกรดระดับความเข้ากันได้หรือรับผลลัพธ์ที่แตกต่าง
ใช้ชื่อคอลัมน์ที่ผ่านการรับรองใน APPLY
ในโหมดความเข้ากันได้ 90 โหมดขึ้นไปคุณสามารถทำได้โดยไม่มีปัญหา:
SELECT * FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t;
อย่างไรก็ตามในโหมดความเข้ากันได้ 80 โหมดคอลัมน์ที่ผ่านการรับรองจะส่งผลให้เกิดข้อผิดพลาดทางไวยากรณ์ทั่วไป:
ข่าวสารเกี่ยวกับ 102 ระดับ 15 สถานะ 1
ไวยากรณ์ไม่ถูกต้องใกล้กับ '.'
เรียงตามชื่อแทนที่ตรงกับชื่อคอลัมน์
พิจารณาคำถามนี้:
SELECT name = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.name;
ใน 80 โหมดที่เข้ากันได้ผลลัพธ์จะเป็นดังนี้:
001_ofni_epytatad_ps sp_datatype_info_100
001_scitsitats_ps sp_statistics_100
001_snmuloc_corps_ps sp_sproc_columns_100
...
ในโหมดความเข้ากันได้ 90 โหมดผลลัพธ์จะแตกต่างกันมาก:
snmuloc_lla all_columns
stcejbo_lla all_objects
sretemarap_lla all_parameters
...
เหตุผล? ในโหมดความเข้ากันได้ 80 โหมดคำนำหน้าตารางจะถูกละเว้นทั้งหมดดังนั้นจึงเป็นการเรียงลำดับโดยนิพจน์ที่กำหนดโดยนามแฝงในSELECT
รายการ ในระดับความเข้ากันได้ที่ใหม่กว่าคำนำหน้าตารางจะถูกนำมาพิจารณาดังนั้น SQL Server จะใช้คอลัมน์นั้นในตารางจริง (หากพบ) หากORDER BY
ไม่พบนามแฝงในตารางระดับความเข้ากันได้ที่ใหม่กว่าจะไม่ให้อภัยเกี่ยวกับความกำกวม ลองพิจารณาตัวอย่างนี้:
SELECT myname = REVERSE(name), realname = name
FROM sys.all_objects AS o
ORDER BY o.myname;
ผลลัพธ์ถูกเรียงลำดับโดยmyname
นิพจน์ใน 80 เนื่องจากไม่มีการละเว้นคำนำหน้าตารางอีกครั้ง แต่ใน 90 จะสร้างข้อความแสดงข้อผิดพลาดนี้:
ข่าวสารเกี่ยวกับ 207, ระดับ 16, สถานะ 1, บรรทัด 3
ชื่อคอลัมน์ไม่ถูกต้อง 'myname'
นี่คือทั้งหมดที่อธิบายไว้ในเอกสารประกอบ :
เมื่อเชื่อมโยงการอ้างอิงคอลัมน์ในORDER BY
รายการกับคอลัมน์ที่กำหนดในSELECT
รายการความคลุมเครือของคอลัมน์จะถูกละเว้นและบางครั้งคำนำหน้าคอลัมน์จะถูกละเว้น นี่อาจทำให้ชุดผลลัพธ์กลับมาเป็นลำดับที่ไม่คาดคิด
ตัวอย่างเช่นORDER BY
อนุประโยคที่มีคอลัมน์สองส่วนเดียว ( <table_alias>.<column>
) ที่ใช้เป็นการอ้างอิงไปยังคอลัมน์ในรายการ SELECT ได้รับการยอมรับ แต่นามแฝงของตารางจะถูกละเว้น พิจารณาคำถามต่อไปนี้
เมื่อดำเนินการคำนำหน้าคอลัมน์จะถูกละเว้นใน
SELECT c1 = -c1 FROM t_table AS x ORDER BY x.c1
ORDER BY
การดำเนินการเรียงลำดับไม่เกิดขึ้นในคอลัมน์แหล่งข้อมูลที่ระบุ ( x.c1
) ตามที่คาดไว้ แทนมันเกิดขึ้นในที่ได้รับc1
คอลัมน์ที่กำหนดไว้ในแบบสอบถาม แผนการดำเนินการสำหรับเคียวรีนี้แสดงให้เห็นว่าค่าสำหรับคอลัมน์ที่ได้รับนั้นจะถูกคำนวณก่อนจากนั้นจะคำนวณค่าที่คำนวณได้
เรียงลำดับโดยบางสิ่งที่ไม่ได้อยู่ในรายการ SELECT
ในโหมดความเข้ากันได้ 90 โหมดคุณไม่สามารถทำได้:
SELECT name = COALESCE(a.name, '') FROM sys.objects AS a
UNION ALL
SELECT name = COALESCE(a.name, '') FROM sys.objects AS a
ORDER BY a.name;
ผลลัพธ์:
ข่าวสารเกี่ยวกับ 104, ระดับ 16, สถานะ 1 เรียง
ลำดับตามรายการจะต้องปรากฏในรายการที่เลือกถ้าคำสั่งมีตัวดำเนินการ UNION, INTERSECT หรือ EXCEPT
อย่างไรก็ตามใน 80 คุณยังคงสามารถใช้ไวยากรณ์นี้ได้
เก่าเข้าร่วมนอก icky
80 โหมดยังช่วยให้คุณใช้ไวยากรณ์การเข้าร่วมด้านนอกที่เลิกใช้แล้ว ( *=/=*
):
SELECT o.name, c.name
FROM sys.objects AS o, sys.columns AS c
WHERE o.[object_id] *= c.[object_id];
ใน SQL Server 2008/2008 R2 หากคุณมีอายุ 90 ปีขึ้นไปคุณจะได้รับข้อความ verbose:
ข่าวสารเกี่ยวกับ 4147 ระดับ 15 สถานะ 1
แบบสอบถามใช้ตัวดำเนินการเข้าร่วมนอกที่ไม่ใช่ ANSI (" *=
" หรือ " =*
") หากต้องการเรียกใช้แบบสอบถามนี้โดยไม่มีการแก้ไขโปรดตั้งค่าระดับความเข้ากันได้สำหรับฐานข้อมูลปัจจุบันเป็น 80 โดยใช้ตัวเลือก SET COMPATIBILITY_LEVEL ของ ALTER DATABASE ขอแนะนำอย่างยิ่งให้เขียนแบบสอบถามใหม่โดยใช้ตัวดำเนินการเข้าร่วมด้านนอกของ ANSI (ซ้ายเข้าร่วมด้านขวาเข้าร่วมด้านนอก) ใน SQL Server รุ่นอนาคตตัวดำเนินการเข้าร่วมที่ไม่ใช่ ANSI จะไม่ได้รับการสนับสนุนแม้ในโหมดความเข้ากันได้แบบย้อนหลัง
ใน SQL Server 2012 นี่ไม่ใช่ไวยากรณ์ที่ถูกต้องอีกต่อไปและให้ผลดังนี้:
ข่าวสารเกี่ยวกับ 102 ระดับ 15 สถานะ 1 บรรทัด 3
ไวยากรณ์ไม่ถูกต้องใกล้ '* ='
แน่นอนใน SQL Server 2012 คุณไม่สามารถแก้ไขปัญหานี้ได้โดยใช้ระดับความเข้ากันได้อีกต่อไปเนื่องจาก 80 ไม่ได้รับการสนับสนุนอีกต่อไป หากคุณอัพเกรดฐานข้อมูลในโหมด 80 compat (โดยการอัพเกรดในสถานที่, ถอด / แนบ, สำรอง / กู้คืน, บันทึกการจัดส่ง, มิเรอร์และอื่น ๆ ) ระบบจะอัปเกรดเป็น 90 สำหรับคุณโดยอัตโนมัติ
คำใบ้ตารางโดยไม่ต้องด้วย
ในโหมดที่เข้ากัน 80 คุณสามารถใช้สิ่งต่อไปนี้และสังเกตคำใบ้ของตาราง:
SELECT * FROM dbo.whatever NOLOCK;
ใน 90+ นั่นNOLOCK
ไม่ใช่คำใบ้ตารางอีกต่อไปมันเป็นนามแฝง มิฉะนั้นจะใช้งานได้:
SELECT * FROM dbo.whatever AS w NOLOCK;
แต่มันไม่ได้:
เกี่ยวกับ 1018 ระดับ 15 สถานะ 1
ไวยากรณ์ไม่ถูกต้องใกล้ 'NOLOCK' หากสิ่งนี้มีวัตถุประสงค์เพื่อเป็นส่วนหนึ่งของคำใบ้ของตารางตอนนี้จำเป็นต้องใช้คำหลัก A และวงเล็บ ดู SQL Server Books Online สำหรับไวยากรณ์ที่เหมาะสม
ตอนนี้เพื่อพิสูจน์ว่าพฤติกรรมดังกล่าวไม่ได้รับการสังเกตในตัวอย่างแรกเมื่ออยู่ในโหมดใช้งานร่วมกัน 90 โหมดให้ใช้ AdventureWorks (ตรวจสอบให้แน่ใจว่าอยู่ในระดับที่เข้ากันได้สูงกว่า) และเรียกใช้สิ่งต่อไปนี้:
BEGIN TRANSACTION;
SELECT TOP (1) * FROM Sales.SalesOrderHeader UPDLOCK;
SELECT * FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
AND resource_type IN ('KEY', 'OBJECT'); -- how many rows here? 0
COMMIT TRANSACTION;
BEGIN TRANSACTION;
SELECT TOP (1) * FROM Sales.SalesOrderHeader WITH (UPDLOCK);
SELECT * FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
AND resource_type IN ('KEY', 'OBJECT'); -- how many rows here? 2
COMMIT TRANSACTION;
อันนี้เป็นปัญหาโดยเฉพาะอย่างยิ่งเพราะพฤติกรรมการเปลี่ยนแปลงโดยไม่มีข้อผิดพลาดหรือแม้กระทั่งข้อผิดพลาด และมันก็เป็นสิ่งที่ที่ปรึกษาการอัพเกรดและเครื่องมืออื่น ๆ อาจไม่เห็นด้วยซ้ำเพราะนั่นคือชื่อแทนตาราง
การแปลงที่เกี่ยวข้องกับประเภทวันที่ / เวลาใหม่
ประเภทวันที่ / เวลาใหม่ที่นำมาใช้ใน SQL Server 2008 (เช่นdate
และdatetime2
) รองรับช่วงที่มีขนาดใหญ่กว่าแบบเดิมdatetime
และsmalldatetime
) การแปลงค่าที่ชัดเจนนอกช่วงที่สนับสนุนจะล้มเหลวไม่ว่าระดับความเข้ากันได้จะเป็นอย่างไรตัวอย่างเช่น:
SELECT CONVERT(SMALLDATETIME, '00010101');
อัตราผลตอบแทน:
ข่าวสารเกี่ยวกับ 242, ระดับ 16, สถานะ 3
การแปลงชนิดข้อมูล varchar เป็นชนิดข้อมูลขนาดเล็กในเวลาทำการส่งผลให้มีค่านอกช่วง
อย่างไรก็ตามการแปลงโดยนัยจะทำงานในระดับความเข้ากันได้ที่ใหม่กว่า เช่นนี้จะทำงานใน 100+:
SELECT DATEDIFF(DAY, CONVERT(SMALLDATETIME, SYSDATETIME()), '00010101');
แต่ใน 80 (และ 90) ก็ให้ข้อผิดพลาดที่คล้ายกันดังกล่าวข้างต้น:
เกี่ยวกับข่าวสาร 242 ระดับ 16 สถานะ 3
การแปลงชนิดข้อมูล varchar เป็นชนิดข้อมูล datetime ส่งผลให้มีค่านอกช่วง
ซ้ำซ้อนสำหรับส่วนคำสั่งในทริกเกอร์
นี่คือสถานการณ์ที่คลุมเครือที่ขึ้นมาที่นี่ ในโหมดความเข้ากันได้ 80 โหมดสิ่งนี้จะสำเร็จ:
CREATE TABLE dbo.x(y INT);
GO
CREATE TRIGGER tx ON dbo.x
FOR UPDATE, UPDATE
------------^^^^^^ notice the redundant UPDATE
AS PRINT 1;
ใน 90 ความเข้ากันได้และสูงกว่านี้จะไม่แยกวิเคราะห์อีกต่อไปและคุณจะได้รับข้อความแสดงข้อผิดพลาดดังนี้:
ข่าวสารเกี่ยวกับ 1034, ระดับ 15, สถานะ 1,
ข้อผิดพลาดของไวยากรณ์กระบวนงาน tx
: ข้อมูลจำเพาะที่ซ้ำกันของการกระทำ "UPDATE" ในการประกาศทริกเกอร์
PIVOT / Unpivot
รูปแบบของไวยากรณ์บางรูปแบบจะไม่ทำงานภายใต้ 80 (แต่ทำงานได้ดีใน 90+):
SELECT col1, col2
FROM dbo.t1
UNPIVOT (value FOR col3 IN ([x],[y])) AS p;
อัตราผลตอบแทนนี้:
ข่าวสารเกี่ยวกับ 156, ระดับ 15, สถานะ 1
ไวยากรณ์ไม่ถูกต้องใกล้กับคำหลัก 'สำหรับ'
สำหรับวิธีการแก้ปัญหาบางอย่างรวมทั้งCROSS APPLY
ดูคำตอบเหล่านี้
ฟังก์ชั่นใหม่ในตัว
ลองใช้ฟังก์ชั่นใหม่ ๆ เช่นTRY_CONVERT()
ในฐานข้อมูลที่มีระดับความเข้ากันได้ <110 พวกมันไม่ได้รับการยอมรับเลย
SELECT TRY_CONVERT(INT, 1);
ผลลัพธ์:
ข่าวสารเกี่ยวกับ 195, ระดับ 15, สถานะ 10
'TRY_CONVERT' ไม่ใช่ชื่อฟังก์ชันในตัวที่ได้รับการยอมรับ
คำแนะนำ
ใช้โหมดความเข้ากันได้ 80 โหมดเท่านั้นหากคุณต้องการใช้งานจริง เนื่องจากจะไม่สามารถใช้งานได้ในรุ่นถัดไปหลังจากปี 2008 R2 สิ่งสุดท้ายที่คุณต้องการทำคือการเขียนโค้ดในระดับการใช้งานร่วมกันนี้ขึ้นอยู่กับพฤติกรรมที่คุณเห็นแล้วมีการแตกหักทั้งหมดเมื่อคุณไม่สามารถ ใช้ระดับที่เข้ากันได้ คิดไปข้างหน้าและอย่าพยายามวาดมุมด้วยการซื้อเวลาเพื่อดำเนินการต่อโดยใช้ไวยากรณ์เก่าที่เลิกใช้แล้ว