- 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
产生这个结果?
Error message: Msg 8180,Level 16,State 1,Line 1
Statement(s) could not be prepared.
Msg 125,Level 15,State 4,Line 1
Case expressions may only be nested to level 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
解决方法
Clearly there isn’t a nested
CASE
expression here.
不在查询文本中,没有.但是解析器总是将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
该查询是本地的(没有链接服务器),Compute Scalar定义以下表达式:
这在本地执行时很好,因为解析器没有看到超过10个级别的嵌套CASE语句(尽管它确实将一个语句传递给本地查询编译的后续阶段).
但是,对于链接服务器,可以将生成的文本发送到远程服务器进行编译.如果是这种情况,远程解析器会看到超过10级深度的嵌套CASE语句,您将收到错误8180.
Another oddity. This inline table-valued function produces the same
error
内联函数就地扩展到原始查询文本中,因此链接服务器的相同错误结果也就不足为奇了.
But a similar multi-statement TVF works fine
相似,但不一样. msTVF涉及到varchar(max)的隐式转换,这恰好会阻止CASE表达式发送到远程服务器.因为CASE是在本地计算的,所以解析器永远不会看到过度嵌套的CASE并且没有错误.如果将表定义从varchar(max)更改为CASE结果的隐式类型 – varchar(2) – 表达式将使用msTVF进行远程处理,您将收到错误.
最终,当远程服务器评估过度嵌套的CASE时,会发生错误.如果未在远程查询迭代器中评估CASE,则不会产生错误.例如,以下包括未远程控制的CONVERT,因此即使使用链接服务器也不会发生错误:
- SELECT CASE CONVERT(varchar(max),SUBSTRING(p.Name,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