【问题标题】:Understanding CTE Semicolon Placement了解 CTE 分号放置
【发布时间】:2020-06-30 14:18:44
【问题描述】:

当我在 SQL Server 中运行此 CTE 时,它说 declare 语句的语法不正确。

;WITH cte as
(
SELECT tblKBFolders.FolderID
from tblKBFolders
where FolderID = @FolderID

UNION ALL

SELECT tblKBFolders.FolderID
FROM tblKBFolders  
INNER JOIN cte
ON cte.FolderID = tblKBFolders.ParentFolderID
)

declare @tblQueryFolders as table (FolderID uniqueidentifier)
insert into @tblQueryFolders
SELECT FolderID From cte;

但如果我将 declare 移到 CTE 之前,它运行得很好。

declare @tblQueryFolders as table (FolderID uniqueidentifier)

;WITH cte as
(
SELECT tblKBFolders.FolderID
from tblKBFolders
where FolderID = @FolderID

UNION ALL

SELECT tblKBFolders.FolderID
FROM tblKBFolders  
INNER JOIN cte
ON cte.FolderID = tblKBFolders.ParentFolderID
)

insert into @tblQueryFolders
SELECT FolderID From cte;

这是为什么呢?

【问题讨论】:

  • 与分号放置无关。第一个示例在数据语句中间(在 CTE 和 insert 之间)有 declare 语句。
  • 除了“这就是它的设计方式”之外,您还在寻找什么答案?
  • 另外,分号是终止符,而不是“开始符”。不要以分号开始您的 CTE,但请以分号结束您的 CTE 之前的语句。
  • @HoneyBadger 是的,我明白这一点。由于某种原因,我已经看到很多这样写的例子......
  • 不,CTE 不像您可以在任何地方声明和使用的变量。 CTE 是一个表达式,仅此而已。 CTE 和 SELECT 确实是并列的。

标签: sql-server tsql common-table-expression


【解决方案1】:

您要求的答案已经在评论中给出:这与分号的位置无关。

重要提示:CTE 的WITH 不能紧跟在没有分号结尾的语句之后。有很多语句,其中WITH-clause 会在语句末尾添加一些内容(查询提示、OPENJSON 之后的WITH 等)。引擎必须猜测这个WITH 是否添加到之前的语句中,或者它是否是CTE 的开始。这就是为什么我们经常看到的原因

;WITH cte AS (...)

这实际上是分号的错误用法。人们把它放在那里,只是为了不要忘记它。无论如何,用分号总是结束 T-SQL 语句被视为更好的风格和最佳实践(并且使用;WITH,因为它实际上添加了一个空语句)。

CTE 只不过是语法糖。将 CTE 的代码放在 FROM(SELECT ...) AS SomeAlias 中大致相同。在大多数情况下,这将导致相同的执行计划。在您必须在多个地方编写相同的FROM(SELECT ) AS SomeAlias 的情况下,它会有所帮助。而且 - 一般来说 - 它使事情更容易阅读和理解。但它无论如何都不能与临时表或表变量相提并论。引擎会将其视为内联代码,您可以在同一语句中独占使用它。

所以这是一样的:

WITH SomeCTE AS(...some query here...)
SELECT SomeCTE.* FROM SomeCTE;


SELECT SomeAlias.* 
FROM (...some query here...) AS SomeAlias;

您的示例看起来就像您将 CTE 视为一种临时表定义,您可以在以下语句中使用它。但这是不正确的。

在 CTE 之后,引擎需要另一个 CTE 或像 SELECTUPDATE 这样的最终语句。

WITH SomeCTE AS(...some query here...)
SELECT * FROM SomeCTE;

WITH SomeCTE AS( ...query... )
    ,AnotherCTE AS ( ...query... )
SELECT * FROM AnotherCTE;

...或使用WITH 子句添加的其他内容:

WITH XMLNAMESPACES( ...namespace declarations...)
    ,SomeCTE AS( ...query... )
SELECT * FROM SomeCTE;

所有这些例子都是一个单一的陈述

DECLARE @Something 放在中间会打破这个概念。

【讨论】:

    猜你喜欢
    • 2017-08-11
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2018-02-03
    • 2013-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多