繁体   English   中英

单个查询中的多个 CTE

[英]Multiple CTE in single query

是否可以将单个查询中的多个 CTE 与arel组合在一起? 我正在寻找获得这样的结果的方法:

WITH cte1 AS (
...
),
WITH RECURSIVE cte2 AS (
...
),
WITH cte3 AS (
...
)
SELECT ... FROM cte3 WHERE ...

如您所见,我有一个递归 CTE 和两个非递归。

在顶部使用关键字WITH 一次 如果您的任何公用表表达式(CTE)是递归的(rCTE),您还必须在顶部添加一次关键字RECURSIVE ,即使并非所有CTE都是递归的:

WITH RECURSIVE
  cte1 AS (...)         -- can still be non-recursive
, cte2 AS (SELECT ...
           UNION ALL
           SELECT ...)  -- recursive term
, cte3 AS (...)
SELECT ... FROM cte3 WHERE ...

手册:

如果指定了RECURSIVE ,则它允许 SELECT子查询按名称引用自身。

大胆强调我的。 而且,更具洞察力:

RECURSIVE另一个作用是不需要对WITH查询进行排序 :查询可以引用列表后面的另一个查询。 (但是,未实现循环引用或相互递归。)如果没有RECURSIVEWITH查询只能引用兄弟WITH WITH列表中较早的查询。

再次强调我的重点。 这意味着当使用RECURSIVE关键字时, WITH子句的顺序毫无意义

顺便说一句,因为cte1cte2没有在外部SELECT引用并且是纯SELECT命令本身(没有附带效果),所以它们永远不会被执行(除非在cte3引用)。

是。 你不重复WITH 你只需使用逗号:

WITH cte1 AS (
...
),
     cte2 AS (
...
),
     cte3 AS (
...
)
SELECT ... FROM 'cte3' WHERE ...

而且:只对字符串和日期常量使用单引号。 不要将它们用于列别名。 无论如何,它们不被允许用于CTE名称。

是的,可以在 SQL 中使用单个 WITH 子句创建多个公用表表达式。 两个不同的 CTE 是使用单个 WITH 子句创建的,并且用逗号分隔以创建多个 CTE。

使用单个采样多个 CTE

With EmpCount1(DeptName,TotalEmployees)
as
  (
   Select DeptName, COUNT(*) as TotalEmployees
   from Tbl_EmpDetails
   join Tbl_Dept Dept
   on Tbl_EmpDetails.DeptId = Dept.DeptId
   WHERE DeptName IN ('BI','DOTNET')
   group by DeptName
  ),
EmpCount2(DeptName,TotalEmployees)
as
  (
   Select DeptName, COUNT(*) as TotalEmployees
   from Tbl_EmpDetails
   join Tbl_Dept Dept
   on Tbl_EmpDetails.DeptId = Dept.DeptId
   WHERE DeptName IN ('JAVA','AI')
   group by DeptName
  )


  Select * from EmpCount1
  UNION
  Select * from EmpCount2

这是使用单个 With 子句创建多个公用表表达式的示例语法。

正如接受的答案正确所说的那样,每个 CTE 链只使用with子句一次。 但是,为了完整起见,我想补充一点,它不会阻止您嵌套 CTE

如果cte2用途cte1cte3用途cte2等,则热膨胀系数之间的依赖关系链是线性的,它被表达为with用3层的CTE。 相反,如果cte2不需要cte1并且两者都只在cte3中需要,则应考虑将它们嵌套在cte3定义下( with cte3 as (with cte1 as (...), cte2 as (...) select...) )。

然后 CTE 的语法反映了 CTE 之间的依赖树,并从字面上可视化了部分数据集的范围,这可以提高可读性并防止范围泄漏错误。 并非所有数据库供应商都支持它,但 Postgres 支持。

例子:

with cte1(id,capital) as (
  values(1,'Prague'),(2,'Bratislava')
), cte2(id,code) as (
  with cte2inner1(id,code) as (
    values(1,'CZ'),(2,'SK')
  ), cte2inner2(id,country) as (
    values(1,'Czech Republic'),(2,'Slovakia')
  )
  select id,country from cte2inner1 join cte2inner2 using (id)
) 
select *
from cte1 join cte2 using (id)
--join cte2inner1  not possible here

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM