是否可以在单个查询中将多个 CTE 与arel
?我正在寻找获得这样结果的方法:
WITH cte1 AS (
...
),
WITH RECURSIVE cte2 AS (
...
),
WITH cte3 AS (
...
)
SELECT ... FROM cte3 WHERE ...
如您所见,我有一个递归 CTE 和两个非递归 CTE。
是否可以在单个查询中将多个 CTE 与arel
?我正在寻找获得这样结果的方法:
WITH cte1 AS (
...
),
WITH RECURSIVE cte2 AS (
...
),
WITH cte3 AS (
...
)
SELECT ... FROM cte3 WHERE ...
如您所见,我有一个递归 CTE 和两个非递归 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
不需要对查询进行排序:一个查询可以引用列表中后面的另一个查询。(但是,没有实现循环引用或相互递归。)如果没有RECURSIVE
,WITH
查询只能引用列表WITH
中较早的同级查询。WITH
再次大胆强调我的。这意味着当使用了关键词时,WITH
从句的顺序是没有意义的。RECURSIVE
顺便说一句,由于cte1
和cte2
在示例中没有在外部引用SELECT
并且本身是普通SELECT
命令(没有附带影响),它们永远不会被执行(除非在 中引用cte3
)。
是的。你不要重复WITH
. 您只需使用逗号:
WITH cte1 AS (
...
),
cte2 AS (
...
),
cte3 AS (
...
)
SELECT ... FROM 'cte3' WHERE ...
并且:仅对字符串和日期常量使用单引号。不要将它们用于列别名。无论如何,它们都不允许用于 CTE 名称。
正如公认的答案正确地说,该with
子句在每个 CTE 链中仅使用一次。但是,为了完整起见,我想补充一点,它不会阻止您嵌套 CTE。
如果cte2
uses cte1
、cte3
usescte2
等,则CTE之间的依赖链是线性的,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
问题原因:在这里,您不必使用多个 WITH 子句来组合多个 CTE。
解决方案:可以在 SQL 中使用单个 WITH 子句创建多个公用表表达式。使用 Single WITH 子句创建两个不同的 CTE,并用逗号分隔以创建多个 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 子句创建多个公用表表达式的示例语法。