如何正确嵌套CTE

Dav*_*ras 7 sql-server

很少有人问过这个问题,但我仍然无法找到正确的答案或正确的方法来做到这一点:

...

;WITH CTE AS
(
  SELECT * FROM ...
)
SELECT *, [dbo].[udf_BetaInv](A, B, C, D) AS 'Loss'
FROM CTE
WHERE (Loss >= @MinRetention)
Run Code Online (Sandbox Code Playgroud)

这不起作用,我无法创建存储过程,显然我不能在WHERE中使用Loss,因为在该范围内不存在.

我想用另一个CTE来包装这个,所以我可以把WHERE放在外面的那个但是似乎不起作用,试过这个:

;WITH CTE AS
(
  SELECT * FROM ...
)
SELECT *, [dbo].[udf_BetaInv(A, B, C, D) AS 'Loss'
FROM CTE,
RESULTS AS
(SELECT * FROM CTE)
  SELECT *
  FROM RESULTS
  WHERE (Loss >= @MinRetention)
Run Code Online (Sandbox Code Playgroud)

但它没有在SQL Server中编译,我得到一个错误,'''错误地放在上面的许多行但没有任何关系,如果我删除第二个CTE它工作正常.

我只想避免代码重复,不想在select和in中调用我的[udf_BetaInv]两次.

Aak*_*shM 14

你有一个SELECT你不应该拥有的中级.这应该工作:

;WITH CTE AS
(
  SELECT * FROM ...
),
RESULTS AS
(
  SELECT *, [dbo].[udf_BetaInv(A, B, C, D) AS 'Loss'
  FROM CTE
)
SELECT *
FROM RESULTS
WHERE (Loss >= @MinRetention)
Run Code Online (Sandbox Code Playgroud)

  • 在您的 CTE 名称中明确命名列不是必需的,而是一种很好的做法,即 .... RESULTS([column names from CTE], loss) .... 稍后您会感谢自己:P。 (2认同)

Mat*_*ton 7

显然,第一个查询的问题是'Loss'只是一个列别名,不能在WHERE子句中使用.你是正确的,在CTE中使用它会避免重复表达.这是你如何做到的;

WITH CTE AS 
( 
    SELECT * FROM ... 
),
CteWithLoss AS ( 
    SELECT *, [dbo].[udf_BetaInv](A, B, C, D) AS 'Loss' 
    FROM CTE
)
SELECT *
FROM CteWithLoss 
WHERE (Loss >= @MinRetention);
Run Code Online (Sandbox Code Playgroud)

在旁注:看看你是否可以打破开始你的CTE定义;WITH的习惯,而是养成用分号结束所有SQL语句的习惯.它更具可读性和更好的实践.