Sql-Server
為什麼連結伺服器在 CASE 表達式中有 10 個分支的限制?
為什麼是這個
CASE
表達式:SELECT CASE column WHEN 'a' THEN '1' WHEN 'b' THEN '2' ... c -> i WHEN 'j' THEN '10' WHEN 'k' THEN '11' END [col] FROM LinkedServer.database.dbo.table
產生這個結果?
錯誤消息:消息 8180,級別 16,狀態 1,行 1
無法準備語句。
Msg 125, Level 15, State 4, Line 1
Case 表達式只能嵌套到級別 10。顯然這裡沒有嵌套
CASE
表達式,儘管有超過 10 個“分支”。另一個怪事。此內聯表值函式產生相同的錯誤:
ALTER FUNCTION [dbo].[fn_MyFunction] ( @var varchar(20) ) RETURNS TABLE AS RETURN ( SELECT CASE column WHEN 'a' THEN '1' WHEN 'b' THEN '2' ... c -> i WHEN 'j' THEN '10' WHEN 'k' THEN '11' END [col] FROM LinkedServer.database.dbo.table )
但是類似的多語句 TVF 可以正常工作:
ALTER FUNCTION [dbo].[fn_MyFunction] ( @var varchar(20) ) RETURNS @result TABLE ( value varchar(max) ) AS BEGIN INSERT INTO @result SELECT CASE column WHEN 'a' THEN '1' WHEN 'b' THEN '2' ... c -> i WHEN 'j' THEN '10' WHEN 'k' THEN '11' END [col] FROM LinkedServer.database.dbo.table RETURN; END
顯然這裡沒有嵌套
CASE
表達式。不在查詢文本中,沒有。但是解析器總是將
CASE
表達式擴展為嵌套形式:SELECT CASE SUBSTRING(p.Name, 1, 1) WHEN 'a' THEN '1' WHEN 'b' THEN '2' WHEN 'c' THEN '3' WHEN 'd' THEN '4' WHEN 'e' THEN '5' WHEN 'f' THEN '6' WHEN 'g' THEN '7' WHEN 'h' THEN '8' WHEN 'i' THEN '9' WHEN 'j' THEN '10' WHEN 'k' THEN '11' END FROM AdventureWorks2012.Production.Product AS p
該查詢是本地的(無連結伺服器),計算標量定義了以下表達式:
這在本地執行時很好,因為解析器看不到
CASE
超過 10 層深度的嵌套語句(儘管它確實將一個傳遞到本地查詢編譯的後期階段)。但是,使用連結伺服器,生成的文本可能會被發送到遠端伺服器進行編譯。如果是這種情況,遠端解析器
CASE
會看到超過 10 層深度的嵌套語句,您會收到錯誤 8180。另一個怪事。此內聯表值函式產生相同的錯誤
內聯函式就地擴展為原始查詢文本,因此連結伺服器會產生相同的錯誤也就不足為奇了。
但是類似的多語句 TVF 工作正常
類似,但不一樣。msTVF 涉及到 的隱式轉換
varchar(max)
,這恰好阻止了將CASE
表達式發送到遠端伺服器。因為CASE
是在本地評估的,所以解析器永遠不會看到過度嵌套CASE
並且沒有錯誤。如果您將表定義從更改為結果varchar(max)
的隱式類型- 表達式將使用 msTVF 進行遠端處理,您將收到錯誤消息。CASE``varchar(2)
CASE
最終,當遠端伺服器評估過度嵌套時會發生錯誤。如果CASE
未在遠端查詢迭代器中評估 ,則不會產生錯誤。例如,以下包括一個CONVERT
未遠端的,因此即使使用連結伺服器也不會發生錯誤:SELECT CASE CONVERT(varchar(max), SUBSTRING(p.Name, 1, 1)) WHEN 'a' THEN '1' WHEN 'b' THEN '2' WHEN 'c' THEN '3' WHEN 'd' THEN '4' WHEN 'e' THEN '5' WHEN 'f' THEN '6' WHEN 'g' THEN '7' WHEN 'h' THEN '8' WHEN 'i' THEN '9' WHEN 'j' THEN '10' WHEN 'k' THEN '11' END FROM SQL2K8R2.AdventureWorks.Production.Product AS p