CASE
biểu thức là một trong những cấu trúc yêu thích của tôi trong T-SQL. Nó khá linh hoạt và đôi khi là cách duy nhất để kiểm soát thứ tự mà SQL Server sẽ đánh giá các vị từ.
Tuy nhiên, nó thường bị hiểu nhầm.
Biểu thức T-SQL CASE là gì?
Trong T-SQL, CASE
là một biểu thức đánh giá một hoặc nhiều biểu thức có thể có và trả về biểu thức thích hợp đầu tiên. Cụm từ biểu thức có thể hơi quá tải ở đây, nhưng về cơ bản nó là bất kỳ thứ gì có thể được đánh giá là một giá trị vô hướng, đơn lẻ, chẳng hạn như một biến, một cột, một chuỗi ký tự hoặc thậm chí là đầu ra của một hàm tích hợp hoặc hàm vô hướng .
Có hai dạng CASE trong T-SQL:
- Biểu thức CASE đơn giản - khi bạn chỉ cần đánh giá bình đẳng:
CASE <input> WHEN <eval> THEN <return> … [ELSE <return>] END
- Biểu thức CASE đã tìm kiếm - khi bạn cần đánh giá các biểu thức phức tạp hơn, chẳng hạn như bất đẳng thức, LIKE hoặc KHÔNG ĐỦ:
CASE WHEN <input_bool> THEN <return> … [ELSE <return>] END
Biểu thức trả về luôn là một giá trị duy nhất và kiểu dữ liệu đầu ra được xác định theo mức độ ưu tiên của kiểu dữ liệu.
Như tôi đã nói, biểu thức CASE thường bị hiểu nhầm; đây là một số ví dụ:
CASE là một biểu thức, không phải là một câu lệnh
Có vẻ như không quan trọng đối với hầu hết mọi người, và có lẽ đây chỉ là khía cạnh lý thuyết của tôi, nhưng nhiều người gọi nó là CASE
tuyên bố - bao gồm cả Microsoft, có tài liệu sử dụng tuyên bố và biểu thức thay thế cho nhau tại các thời điểm. Tôi thấy điều này hơi khó chịu (như hàng / bản ghi và cột / trường ) và, mặc dù nó chủ yếu là ngữ nghĩa, nhưng có một sự khác biệt quan trọng giữa một biểu thức và một câu lệnh:một biểu thức trả về một kết quả. Khi mọi người nghĩ về CASE
như một tuyên bố , nó dẫn đến các thử nghiệm trong việc rút ngắn mã như thế này:
SELECT CASE [status] WHEN 'A' THEN StatusLabel = 'Authorized', LastEvent = AuthorizedTime WHEN 'C' THEN StatusLabel = 'Completed', LastEvent = CompletedTime END FROM dbo.some_table;
Hoặc cái này:
SELECT CASE WHEN @foo = 1 THEN (SELECT foo, bar FROM dbo.fizzbuzz) ELSE (SELECT blat, mort FROM dbo.splunge) END;
Loại logic điều khiển luồng này có thể có với CASE
tuyên bố bằng các ngôn ngữ khác (như VBScript), nhưng không phải trong CASE
của Transact-SQL biểu thức . Để sử dụng CASE
trong cùng một logic truy vấn, bạn sẽ phải sử dụng CASE
biểu thức cho mỗi cột đầu ra:
SELECT StatusLabel = CASE [status] WHEN 'A' THEN 'Authorized' WHEN 'C' THEN 'Completed' END, LastEvent = CASE [status] WHEN 'A' THEN AuthorizedTime WHEN 'C' THEN CompletedTime END FROM dbo.some_table;
CASE sẽ không phải lúc nào cũng ngắn mạch
Tài liệu chính thức đã từng ngụ ý rằng toàn bộ biểu thức sẽ ngắn mạch, có nghĩa là nó sẽ đánh giá biểu thức từ trái sang phải và ngừng đánh giá khi nó gặp một kết quả phù hợp:
Câu lệnh CASE [sic!] Đánh giá các điều kiện của nó một cách tuần tự và dừng với điều kiện đầu tiên có điều kiện được thỏa mãn.Tuy nhiên, điều này không phải lúc nào cũng đúng. Và để ghi nhận, trong một phiên bản mới hơn, trang đã tiếp tục cố gắng giải thích một trường hợp mà điều này không được đảm bảo. Nhưng nó chỉ là một phần của câu chuyện:
Trong một số tình huống, một biểu thức được đánh giá trước khi câu lệnh CASE [sic!] Nhận kết quả của biểu thức làm đầu vào của nó. Có thể có sai sót khi đánh giá các biểu thức này. Các biểu thức tổng hợp xuất hiện trong các đối số WHEN của câu lệnh CASE [sic!] Được đánh giá đầu tiên, sau đó được cung cấp cho câu lệnh CASE [sic!]. Ví dụ:truy vấn sau đây tạo ra lỗi chia cho 0 khi tạo ra giá trị của tổng hợp MAX. Điều này xảy ra trước khi đánh giá biểu thức CASE.Ví dụ về phép chia cho số 0 khá dễ tái tạo và tôi đã chứng minh điều đó trong câu trả lời này trên dba.stackexchange.com:
DECLARE @i INT = 1; SELECT CASE WHEN @i = 1 THEN 1 ELSE MIN(1/0) END;
Kết quả:
Msg 8134, Mức 16, Trạng thái 1Đã gặp lỗi chia cho 0.
Có những cách giải quyết nhỏ nhặt (chẳng hạn như ELSE (SELECT MIN(1/0)) END
), nhưng điều này thực sự gây ngạc nhiên cho nhiều người chưa ghi nhớ những câu trên từ Books Online. Lần đầu tiên tôi được biết về kịch bản cụ thể này trong một cuộc trò chuyện về danh sách phân phối e-mail riêng của Itzik Ben-Gan (@ItzikBenGan), người lần lượt được Jaime Lafargue thông báo ban đầu. Tôi đã báo cáo lỗi trong Connect # 690017:CASE / COALESCE không phải lúc nào cũng đánh giá theo thứ tự văn bản; nó nhanh chóng được đóng lại với tên "Theo thiết kế". Paul White (blog | @SQL_Kiwi) sau đó đã đệ trình Connect # 691535:Các tổng thể không tuân theo ngữ nghĩa của CASE, và nó đã bị đóng là "Đã sửa." Cách khắc phục, trong trường hợp này, đã được làm rõ trong bài báo Sách trực tuyến; cụ thể là đoạn mã tôi đã sao chép ở trên.
Hành vi này cũng có thể tự mang lại trong một số trường hợp khác, ít rõ ràng hơn. Ví dụ:Connect # 780132:FREETEXT () không tuân theo thứ tự đánh giá trong câu lệnh CASE (không liên quan đến tổng hợp) cho thấy rằng CASE
Thứ tự đánh giá cũng không được đảm bảo là từ trái sang phải khi sử dụng một số hàm toàn văn. Về mục đó, Paul White nhận xét rằng ông cũng quan sát thấy điều gì đó tương tự bằng cách sử dụng LAG()
mới được giới thiệu trong SQL Server 2012. Tôi không có bản repro hữu ích, nhưng tôi tin anh ấy và tôi không nghĩ rằng chúng tôi đã khai quật được tất cả các trường hợp phức tạp mà điều này có thể xảy ra.
Vì vậy, khi liên quan đến tổng hợp hoặc các dịch vụ không phải gốc như Tìm kiếm toàn văn bản, vui lòng không đưa ra bất kỳ giả định nào về hiện tượng đoản mạch trong CASE
biểu thức.
RAND () có thể được đánh giá nhiều lần
Tôi thường thấy mọi người viết một đơn giản CASE
biểu thức, như thế này:
SELECT CASE @variable WHEN 1 THEN 'foo' WHEN 2 THEN 'bar' END
Điều quan trọng là phải hiểu rằng điều này sẽ được thực thi dưới dạng đã tìm kiếm CASE
biểu thức, như thế này:
SELECT CASE WHEN @variable = 1 THEN 'foo' WHEN @variable = 2 THEN 'bar' END
Lý do quan trọng phải hiểu rằng biểu thức đang được đánh giá sẽ được đánh giá nhiều lần, là vì nó thực sự có thể được đánh giá nhiều lần. Khi đây là một biến, hoặc một hằng số, hoặc một tham chiếu cột, thì đây không phải là một vấn đề thực sự; tuy nhiên, mọi thứ có thể thay đổi nhanh chóng khi nó là một hàm không xác định. Hãy xem xét rằng biểu thức này mang lại SMALLINT
từ 1 đến 3; hãy tiếp tục và chạy nó nhiều lần, và bạn sẽ luôn nhận được một trong ba giá trị đó:
SELECT CONVERT(SMALLINT, 1+RAND()*3);
Bây giờ, hãy đặt nó vào một CASE
đơn giản và chạy nó hàng chục lần - cuối cùng bạn sẽ nhận được kết quả là NULL
:
SELECT [result] = CASE CONVERT(SMALLINT, 1+RAND()*3) WHEN 1 THEN 'one' WHEN 2 THEN 'two' WHEN 3 THEN 'three' END;
Làm thế nào điều này xảy ra? Chà, toàn bộ CASE
biểu thức được mở rộng thành một biểu thức được tìm kiếm, như sau:
SELECT [result] = CASE WHEN CONVERT(SMALLINT, 1+RAND()*3) = 1 THEN 'one' WHEN CONVERT(SMALLINT, 1+RAND()*3) = 2 THEN 'two' WHEN CONVERT(SMALLINT, 1+RAND()*3) = 3 THEN 'three' ELSE NULL -- this is always implicitly there END;
Đổi lại, điều xảy ra là mỗi WHEN
mệnh đề đánh giá và gọi RAND()
độc lập - và trong mỗi trường hợp, nó có thể mang lại một giá trị khác nhau. Giả sử chúng tôi nhập biểu thức và chúng tôi kiểm tra WHEN
đầu tiên mệnh đề, và kết quả là 3; chúng ta bỏ qua điều khoản đó và tiếp tục. Có thể hình dung rằng cả hai mệnh đề tiếp theo sẽ trả về 1 khi RAND()
được đánh giá lại - trong trường hợp này không có điều kiện nào được đánh giá là true, vì vậy ELSE
tiếp quản.
Các biểu thức khác có thể được đánh giá nhiều lần
Sự cố này không chỉ giới hạn ở RAND()
hàm số. Hãy tưởng tượng cùng một kiểu thuyết phi quyết định đến từ các mục tiêu di động này:
SELECT [crypt_gen] = 1+ABS(CRYPT_GEN_RANDOM(10) % 20), [newid] = LEFT(NEWID(),2), [checksum] = ABS(CHECKSUM(NEWID())%3);
Các biểu thức này rõ ràng có thể mang lại một giá trị khác nếu được đánh giá nhiều lần. Và với một CASE
được tìm kiếm , sẽ có lúc mọi đánh giá lại không nằm ngoài tìm kiếm cụ thể cho WHEN
hiện tại và cuối cùng nhấn ELSE
mệnh đề. Để bảo vệ bạn khỏi điều này, một tùy chọn là luôn viết mã cố định ELSE
rõ ràng của riêng bạn; chỉ cần cẩn thận về giá trị dự phòng bạn chọn để trả lại, vì điều này sẽ có một số hiệu ứng lệch nếu bạn đang tìm kiếm phân phối đồng đều. Một tùy chọn khác là chỉ thay đổi WHEN
cuối cùng mệnh đề đến ELSE
, nhưng điều này vẫn sẽ dẫn đến phân phối không đồng đều. Tùy chọn ưu tiên, theo ý kiến của tôi, là thử và ép buộc SQL Server đánh giá điều kiện một lần (mặc dù điều này không phải lúc nào cũng có thể thực hiện được trong một truy vấn). Ví dụ:so sánh hai kết quả sau:
-- Query A: expression referenced directly in CASE; no ELSE: SELECT x, COUNT(*) FROM ( SELECT x = CASE ABS(CHECKSUM(NEWID())%3) WHEN 0 THEN '0' WHEN 1 THEN '1' WHEN 2 THEN '2' END FROM sys.all_columns ) AS y GROUP BY x; -- Query B: additional ELSE clause: SELECT x, COUNT(*) FROM ( SELECT x = CASE ABS(CHECKSUM(NEWID())%3) WHEN 0 THEN '0' WHEN 1 THEN '1' WHEN 2 THEN '2' ELSE '2' END FROM sys.all_columns ) AS y GROUP BY x; -- Query C: Final WHEN converted to ELSE: SELECT x, COUNT(*) FROM ( SELECT x = CASE ABS(CHECKSUM(NEWID())%3) WHEN 0 THEN '0' WHEN 1 THEN '1' ELSE '2' END FROM sys.all_columns ) AS y GROUP BY x; -- Query D: Push evaluation of NEWID() to subquery: SELECT x, COUNT(*) FROM ( SELECT x = CASE x WHEN 0 THEN '0' WHEN 1 THEN '1' WHEN 2 THEN '2' END FROM ( SELECT x = ABS(CHECKSUM(NEWID())%3) FROM sys.all_columns ) AS x ) AS y GROUP BY x;
Phân phối:
Giá trị | Truy vấn A | Truy vấn B | Truy vấn C | Truy vấn D |
---|---|---|---|---|
KHÔNG ĐỦ | 2,572 | - | - | - |
0 | 2.923 | 2.900 | 2.928 | 2.949 |
1 | 1.946 | 1.959 | 1.927 | 2.896 |
2 | 1.295 | 3.877 | 3.881 | 2.891 |
Phân phối giá trị bằng các kỹ thuật truy vấn khác nhau
Trong trường hợp này, tôi dựa vào thực tế là SQL Server đã chọn đánh giá biểu thức trong truy vấn con và không giới thiệu nó với CASE
đã tìm kiếm nhưng điều này chỉ để chứng minh rằng phân phối có thể bị ép buộc để đồng đều hơn. Trong thực tế, đây có thể không phải lúc nào cũng là lựa chọn mà trình tối ưu hóa đưa ra, vì vậy vui lòng không học từ thủ thuật nhỏ này. :-)
CHOOSE () cũng bị ảnh hưởng
Bạn sẽ thấy điều đó nếu bạn thay thế CHECKSUM(NEWID())
biểu thức với RAND()
biểu thức, bạn sẽ nhận được các kết quả hoàn toàn khác; đáng chú ý nhất, sau này sẽ chỉ trả về một giá trị. Điều này là do RAND()
, như GETDATE()
và một số hàm tích hợp khác, được xử lý đặc biệt như một hằng số thời gian chạy và chỉ được đánh giá một lần trên mỗi tham chiếu cho toàn bộ hàng. Lưu ý rằng nó vẫn có thể trả về NULL
giống như truy vấn đầu tiên trong mẫu mã trước đó.
Vấn đề này cũng không chỉ giới hạn ở CASE
biểu hiện; bạn có thể thấy hành vi tương tự với các hàm tích hợp khác sử dụng cùng ngữ nghĩa cơ bản. Ví dụ:CHOOSE
chỉ đơn thuần là đường cú pháp cho một CASE
được tìm kiếm phức tạp hơn và điều này cũng sẽ mang lại NULL
thỉnh thoảng:
SELECT [choose] = CHOOSE(CONVERT(SMALLINT, 1+RAND()*3),'one','two','three');
IIF()
là một hàm mà tôi dự kiến sẽ rơi vào cùng một cái bẫy này, nhưng hàm này thực sự chỉ là một CASE
được tìm kiếm biểu thức chỉ có hai kết quả có thể xảy ra và không có ELSE
- vì vậy thật khó, nếu không lồng ghép và giới thiệu các chức năng khác, để hình dung một kịch bản mà điều này có thể bị phá vỡ bất ngờ. Trong trường hợp đơn giản, nó là viết tắt phù hợp cho CASE
, cũng rất khó để làm bất cứ điều gì hữu ích với nó nếu bạn cần nhiều hơn hai kết quả có thể xảy ra. :-)
COALESCE () cũng bị ảnh hưởng
Cuối cùng, chúng ta nên kiểm tra COALESCE
đó có thể có các vấn đề tương tự. Hãy coi rằng các biểu thức này là tương đương:
SELECT COALESCE(@variable, 'constant'); SELECT CASE WHEN @variable IS NOT NULL THEN @variable ELSE 'constant' END);
Trong trường hợp này, @variable
sẽ được đánh giá hai lần (cũng như bất kỳ hàm hoặc truy vấn con nào, như được mô tả trong mục Kết nối này).
Tôi thực sự có thể nhận được một số cái nhìn khó hiểu khi tôi đưa ra ví dụ sau đây trong một cuộc thảo luận diễn đàn gần đây. Giả sử tôi muốn điền một bảng có phân phối giá trị từ 1-5, nhưng bất cứ khi nào gặp 3, tôi muốn sử dụng -1 thay thế. Không phải là một kịch bản thực tế, nhưng dễ xây dựng và theo dõi. Một cách để viết biểu thức này là:
SELECT COALESCE(NULLIF(CONVERT(SMALLINT,1+RAND()*5),3),-1);
(Bằng tiếng Anh, làm việc từ trong ra ngoài:chuyển đổi kết quả của biểu thức 1+RAND()*5
đến một người thợ rèn; nếu kết quả của chuyển đổi đó là 3, hãy đặt nó thành NULL
; nếu kết quả của điều đó là NULL
, đặt nó thành -1. Bạn có thể viết điều này với một CASE
dài dòng hơn diễn đạt, nhưng ngắn gọn dường như là vua.)
Nếu bạn chạy nhiều lần như vậy, bạn sẽ thấy một loạt các giá trị từ 1-5, cũng như -1. Bạn sẽ thấy một số trường hợp của 3 và bạn cũng có thể nhận thấy rằng bạn thỉnh thoảng thấy NULL
, mặc dù bạn có thể không mong đợi một trong hai kết quả đó. Hãy kiểm tra phân phối:
USE tempdb; GO CREATE TABLE dbo.dist(TheNumber SMALLINT); GO INSERT dbo.dist(TheNumber) SELECT COALESCE(NULLIF(CONVERT(SMALLINT,1+RAND()*5),3),-1); GO 10000 SELECT TheNumber, occurences = COUNT(*) FROM dbo.dist GROUP BY TheNumber ORDER BY TheNumber; GO DROP TABLE dbo.dist;
Kết quả (kết quả của bạn chắc chắn sẽ khác nhau, nhưng xu hướng cơ bản phải tương tự):
TheNumber | lần xuất hiện |
---|---|
NULL | 1.654 |
- 1 | 2,002 |
1 | 1.290 |
2 | 1,266 |
3 | 1.287 |
4 | 1.251 |
5 | 1.250 |
Phân phối TheNumber bằng COALESCE
Chia nhỏ biểu thức CASE đã tìm kiếm
Bạn đang vò đầu bứt tai chưa? Làm thế nào để các giá trị NULL
và 3 hiển thị và tại sao phân phối cho NULL
và -1 cao hơn đáng kể? Chà, tôi sẽ trả lời trực tiếp câu trước và đưa ra giả thuyết cho phần sau.
Biểu thức gần như mở rộng thành sau, theo logic, vì RAND()
được đánh giá hai lần bên trong NULLIF
, và sau đó nhân nó với hai đánh giá cho mỗi nhánh của COALESCE
hàm số. Tôi không có trình gỡ lỗi tiện dụng, vì vậy đây không nhất thiết phải * chính xác * những gì được thực hiện bên trong SQL Server, nhưng nó phải đủ tương đương để giải thích điểm:
SELECT CASE WHEN CASE WHEN CONVERT(SMALLINT,1+RAND()*5) = 3 THEN NULL ELSE CONVERT(SMALLINT,1+RAND()*5) END IS NOT NULL THEN CASE WHEN CONVERT(SMALLINT,1+RAND()*5) = 3 THEN NULL ELSE CONVERT(SMALLINT,1+RAND()*5) END ELSE -1 END END
Vì vậy, bạn có thể thấy rằng việc được đánh giá nhiều lần có thể nhanh chóng trở thành cuốn sách Choose Your Own Adventure ™ và cả hai NULL
và 3 là những kết quả có thể xảy ra mà dường như không thể xảy ra khi xem xét tuyên bố ban đầu. Một lưu ý phụ thú vị:điều này không xảy ra hoàn toàn giống nhau nếu bạn lấy tập lệnh phân phối ở trên và thay thế COALESCE
với ISNULL
. Trong trường hợp đó, không có khả năng xảy ra NULL
đầu ra; phân phối gần như sau:
TheNumber | lần xuất hiện |
---|---|
- 1 | 1.966 |
1 | 1.585 |
2 | 1.644 |
3 | 1.573 |
4 | 1.598 |
5 | 1,634 |
Phân phối TheNumber bằng ISNULL
Một lần nữa, kết quả thực tế của bạn chắc chắn sẽ khác nhau, nhưng không quá nhiều. Vấn đề là chúng ta vẫn có thể thấy 3 lần rơi qua các vết nứt khá thường xuyên, nhưng ISNULL
loại bỏ tiềm năng NULL
một cách kỳ diệu để làm cho nó thông suốt.
Tôi đã nói về một số khác biệt khác giữa COALESCE
và ISNULL
trong một mẹo, có tên "Quyết định giữa COALESCE và ISNULL trong SQL Server." Khi tôi viết điều đó, tôi rất ủng hộ việc sử dụng COALESCE
ngoại trừ trường hợp đối số đầu tiên là một truy vấn con (một lần nữa, do lỗi này "khoảng cách tính năng"). Bây giờ tôi không chắc mình cảm thấy mạnh mẽ về điều đó.
Các biểu thức CASE đơn giản có thể được lồng vào các máy chủ được liên kết
Một trong những hạn chế của CASE
biểu thức được giới hạn ở 10 cấp độ tổ. Trong ví dụ này trên dba.stackexchange.com, Paul White chứng minh (sử dụng Plan Explorer) rằng một biểu thức đơn giản như sau:
SELECT CASE column_name WHEN '1' THEN 'a' WHEN '2' THEN 'b' WHEN '3' THEN 'c' ... END FROM ...
Được trình phân tích cú pháp mở rộng thành biểu mẫu đã tìm kiếm:
SELECT CASE WHEN column_name = '1' THEN 'a' WHEN column_name = '2' THEN 'b' WHEN column_name = '3' THEN 'c' ... END FROM ...
Nhưng thực sự có thể được truyền qua kết nối máy chủ được liên kết như sau, truy vấn chi tiết hơn nhiều:
SELECT CASE WHEN column_name = '1' THEN 'a' ELSE CASE WHEN column_name = '2' THEN 'b' ELSE CASE WHEN column_name = '3' THEN 'c' ELSE ... ELSE NULL END END END FROM ...
Trong trường hợp này, mặc dù truy vấn ban đầu chỉ có một CASE
duy nhất biểu thức với hơn 10 kết quả có thể có, khi được gửi đến máy chủ được liên kết, nó có hơn 10 lồng nhau CASE
biểu thức. Do đó, như bạn có thể mong đợi, nó trả về một lỗi:
.
Câu lệnh Msg 125, Mức 15, Trạng thái 4
chỉ có thể được lồng vào mức 10.
Trong một số trường hợp, bạn có thể viết lại nó như Paul đã đề xuất, với một biểu thức như thế này (giả sử column_name
là một cột varchar):
SELECT CASE CONVERT(VARCHAR(MAX), SUBSTRING(column_name, 1, 255)) WHEN 'a' THEN '1' WHEN 'b' THEN '2' WHEN 'c' THEN '3' ... END FROM ...
Trong một số trường hợp, chỉ SUBSTRING
có thể được yêu cầu thay đổi vị trí nơi biểu thức được đánh giá; ở những người khác, chỉ CONVERT
. Tôi đã không thực hiện kiểm tra toàn diện, nhưng điều này có thể liên quan đến nhà cung cấp máy chủ được liên kết, các tùy chọn như đối chiếu Tương thích và Sử dụng đối chiếu từ xa và phiên bản của SQL Server ở một trong hai đầu của đường dẫn.
Câu chuyện ngắn, điều quan trọng cần nhớ là CASE
của bạn biểu thức có thể được viết lại cho bạn mà không cần cảnh báo và rằng bất kỳ giải pháp nào bạn sử dụng sau này có thể bị trình tối ưu hóa thay thế, ngay cả khi nó phù hợp với bạn bây giờ.
Ý tưởng cuối cùng của diễn đạt trong CASE và các tài nguyên bổ sung
Tôi hy vọng tôi đã cho một số thực phẩm để suy nghĩ về một số khía cạnh ít được biết đến của CASE
biểu thức và một số thông tin chi tiết về các tình huống trong đó CASE
- và một số hàm sử dụng cùng một logic cơ bản - trả về kết quả không mong đợi. Một số tình huống thú vị khác trong đó loại vấn đề này đã xảy ra:
- Stack Overflow:Làm cách nào để biểu thức CASE này tiếp cận mệnh đề ELSE?
- Tràn ngăn xếp:CRYPT_GEN_RANDOM () Hiệu ứng lạ
- Tràn ngăn xếp:CHOOSE () Không hoạt động như dự định
- Stack Overflow:CHECKSUM (NewId ()) thực thi nhiều lần trên mỗi hàng
- Kết nối # 350485:Lỗi với NEWID () và Biểu thức bảng