调整查询以使用 CTE

Posted

技术标签:

【中文标题】调整查询以使用 CTE【英文标题】:Adapting query to use CTE 【发布时间】:2019-01-31 02:02:24 【问题描述】:

我正在寻找在查询中使用 CTE,因为我得到了相同的选择,但我以前从未使用过 CTE,有人可以帮助我吗?

我需要 firstTable 可以在其他选择中使用

SELECT firstTable.id as id,
   secondTable.holder as holder
FROM (
select tb3.id as id
from table1 tb1
inner join table2 tb2 on tb1.tb2_id = tb2.id
inner join table3 tb3 on tb2.tb3_id = tb3.id and tb3.id
inner join table4 tb4 on tb4.id = tb3.tb4_id and tb4.id = 1998
group by tb3.id) as firstTable
JOIN (
select id_holder,
       sum(temporaryTable.holder) as holder
from (
    select cast(tb4.helper as integer) as helper,
           count(distinct tb4.id) as holder,
           tb3.id as id_holder
    from table1 tb1
    inner join table2 tb2 on tb1.tb2_id = tb2.id
    inner join table3 tb3 on tb2.tb3_id = tb3.id and tb3.id
    inner join table4 tb4 on tb4.id = tb3.tb4_id and tb4.id = 1998
    group by tb3.id, tb4.helper
) as temporaryTable
where temporaryTable.helper between 7 and 8
group by id_holder) as secondTable
ON firstTable.id = temporaryTable.id_holder

这是我的尝试查询:

WITH temporary_table AS
  ( SELECT id,
           cast(resp.valor AS integer) AS holder,
           count(val) AS sumId
   FROM table1 tb1
   INNER JOIN table2 tb2 ON tb1.tb2_id = tb2.id
   INNER JOIN table3 tb3 ON tb2.tb3_id = tb3.id
   AND tb3.id
   INNER JOIN table4 tb4 ON tb4.id = tb3.tb4_id
   AND tb4.id = 1998
   GROUP BY tb3.id )
SELECT
  (SELECT SUM(sumId)
   WHERE holder = -10) AS p1,

  (SELECT SUM(sumId)
   WHERE holder = 78) AS p2,

  (SELECT SUM(sumId)
   WHERE holder = 1997) AS p3,
       id
FROM temporary_table
GROUP BY id,
         holder;

【问题讨论】:

可以参考CTEdocpostgresql.org/docs/9.1/queries-with.html 我是,但我不能把我的“where”子句放在最后:/它不起作用 如果你在这里发布你的no working 会更好。我们很高兴帮助您解决这个问题,而不仅仅是为您编写所有这些 cte @PhamX.Bach 我会编辑问题 您的CTE 查询似乎不等于您的第一个查询。即使您不使用CTE,您的SELECT (select SUM(sumId) where holder = -10) as p1, 也将不起作用。您应该将其更改为 SELECT SUM(CASE WHEN holder = -10 THEN sumId END) AS p1, 而不是按持有者分组 【参考方案1】:

试试这个查询:

select tb3.id as id,
       count(distinct CASE WHEN tb4.helper between 7 and 8 THEN tb4.id END) as holder,
from table1 tb1
inner join table2 tb2 on tb1.tb2_id = tb2.id
inner join table3 tb3 on tb2.tb3_id = tb3.id and tb3.id
inner join table4 tb4 on tb4.id = tb3.tb4_id and tb4.id = 1998
group by tb3.id

【讨论】:

【参考方案2】:

对每个子查询使用 CTE 非常简单:

WITH firstTable AS (
    select tb3.id as id
    from table1 tb1
        inner join table2 tb2 on tb1.tb2_id = tb2.id
        inner join table3 tb3 on tb2.tb3_id = tb3.id and tb3.id
        inner join table4 tb4 on tb4.id = tb3.tb4_id and tb4.id = 1998
    group by tb3.id
), temporaryTable AS (
    select cast(tb4.helper as integer) as helper,
           count(distinct tb4.id) as holder,
           tb3.id as id_holder
    from table1 tb1
        inner join table2 tb2 on tb1.tb2_id = tb2.id
        inner join table3 tb3 on tb2.tb3_id = tb3.id and tb3.id
        inner join table4 tb4 on tb4.id = tb3.tb4_id and tb4.id = 1998
    group by tb3.id, tb4.helper
), secondTable AS (
select id_holder,
       sum(temporaryTable.holder) as holder
from temporaryTable
where temporaryTable.helper between 7 and 8
group by id_holder
)
    SELECT firstTable.id as id,
       secondTable.holder as holder
    FROM firstTable
        JOIN secondTable
            ON firstTable.id = temporaryTable.id_holder;

【讨论】:

谢谢!它比另一个更具有性能,对吧? CTE 可以帮助提高查询的可读性,但不会加快查询速度。如果有的话,我在我的经验中看到,就像其他答案一样,索引并不总是在您期望的时候得到正确利用。为了提高性能,请考虑额外的索引或临时表是否有用。 @t9217:有时 CTE 使事情变得更快,有时它们使事情变慢,有时它们对性能没有任何影响。找出答案的唯一方法是为每个版本运行 explain (analyze) 并亲自查看。【参考方案3】:

我将仅提供问题本身的切线。

我强烈建议您不要使用 CTE。如果您想要一个看起来不错的优雅查询,我相信正确格式化您的查询会更好。 http://www.dpriver.com/pp/sqlformat.htm

CTE 有一个固有的问题是速度很慢,因为在大多数情况下索引都没有正确触发。多年来,我一直从事 SQL 作为职业,在 CTE 中遇到了很多性能问题。使 CTE 更快是困难的,我认为不值得付出努力。它们也使调试和测试查询变得很痛苦,尤其是当 CTE 中有很多表时。很难划分子查询,尤其是测试前一个子查询的假设是否仍然有效。

您还可以在 *** 中查看以下至少 500 多个关于 CTE 速度慢的问题: https://***.com/search?q=slow+cte

我的建议是将数据放在临时表中。您还可以通过重用临时表来删除重复的代码。作为获得更好性能的额外奖励,您可以在临时表中创建索引。您不能在 CTE 中动态创建索引。在我看来,使用 CTE 的唯一原因是递归 CTE。 https://www.essentialsql.com/recursive-ctes-explained/

【讨论】:

以上是关于调整查询以使用 CTE的主要内容,如果未能解决你的问题,请参考以下文章

无法计算 CTE 子查询输出之间的差异以用于更大的 PostgreSQL 查询输出列

递归 CTE 存在性能问题,需要建议以优化查询

如何在不使用 join 或 cte 的情况下在同一查询中使用动态生成的列

优化sql嵌套查询,使用CTE语法

CTE 和子查询的区别?

何时使用公用表表达式 (CTE)