我可以在同一个 WITH 查询中 select 多个表吗?

Can I select several tables in the same WITH query?

我有一个具有 with 结构的长查询。最后,我想输出两个 table。这可能吗?

(顺便说一句,tables 和查询在雪花 SQL 中。)

代码如下所示:

with table_a as (
               select id, 
                      product_a
               from x.x ),
     table_b as (
               select id, 
                      product_b
               from x.y ),
     table_c as ( 

..... many more alias tables and subqueries here .....

             )

select * from table_g where z = 3 ;

但是对于最后一行,我想查询 table_g 两次,一次使用 z = 3,一次使用另一个条件,所以我得到两个 table 作为结果。有没有一种方法可以做到这一点(以两个查询而不是一个查询结束),或者我是否必须重新 运行 我想要作为输出的每个 table 的整个代码?

一个查询 = 一个结果集。这正是 RDBMS 的工作方式。

CTE(WITH 语句)只是子查询的语法糖。

例如,类似于您的查询:

with table_a as (
               select id, 
                      product_a
               from x.x ),
     table_b as (
               select id, 
                      product_b
               from x.y ),
     table_c as (     
               select id, 
                      product_c
               from x.z ),

select * 
from table_a
   inner join table_b on table_a.id = table_b.id
   inner join table_c on table_b.id = table_c.id;

与以下内容 100% 相同:

select *
from
  (select id, product_a from x.x) table_a
  inner join (select id, product_b from x.y) table_b
      on table_a.id = table_b.id
  inner join (select id, product_c from x.z) table_c
      on table_b.id = table_c.id

CTE 版本不会为您提供非 cte 版本中不可用的任何额外功能(递归 cte 除外),并且执行路径将 100% 相同(编辑:请请参阅下面的 Simon 的回答和评论,他指出 Snowflake 可能会具体化 CTE 定义的派生 table,因此如果在主查询中多次引用 CTE,它只需执行该步骤一次)。因此,仍然无法从单个查询中获取第二个结果集。

虽然它们在语法上相同,但它们没有相同的性能计划。

第一种情况可能是 CTE 中的一个阶段很昂贵,并且通过其他 CTE 重复使用或多次加入,在 Snowflake 下,将它们用作 CTE 我亲眼目睹了 运行 "expensive" 部分只有一次,这可能很好,例如像这样。

WITH expensive_select AS (
    SELECT a.a, b.b, c.c
    FROM table_a AS a
    JOIN table_b AS b
    JOIN table_c AS c
    WHERE complex_filters
), do_some_thing_with_results AS (
    SELECT stuff
    FROM expensive_select
    WHERE filters_1
), do_some_agregation AS (
    SELECT a, SUM(b) as sum_b
    FROM expensive_select
    WHERE filters_2
)
SELECT a.a
    ,a.b
    ,b.stuff
    ,c.sum_b
FROM expensive_select AS a
LEFT JOIN do_some_thing_with_results AS b ON a.a = b.a
LEFT JOIN do_some_agregation AS c ON a.a = b.a;

这最初是展开的,昂贵的部分是一些视图,即在顶层应用的日期 运行ge 过滤器没有被下推(由于 window 函数)所以结果 table 多次完整扫描。在将他们推入 CTE 的地方,成本只支付了一次。 (在我们的例子中,在 CTE 中放置日期 运行ge 过滤器使 Snowflake 注意到过滤器并将它们向下推送到视图中,事情可能会发生变化,几周后原始代码 运行 与修改了,所以他们 "fixed" something)

在其他情况下,像这样使用 CTE 的不同路径使用较小的结果子集,因此使用 CTE 减少了远程 IO,从而提高了性能,然后执行计划中出现了更多停顿。

我也使用这样的 CTE 来使代码更易于阅读,但为 CTE 提供了一个有意义的名称,但将其别名为简短的名称以供使用。真的很喜欢。