我有一个查询,看起来像这样
WITH sub_base AS (
SELECT type,
CASE WHEN a < 10 THEN 'GOOD'
WHEN a BETWEEN 10 AND 100 THEN 'OK'
ELSE 'BAD'
END AS a_q,
...
CASE WHEN z < 5 THEN 'GOOD'
WHEN z BETWEEN 5 AND 50 THEN 'OK'
ELSE 'BAD'
END AS z_q
FROM tbl
),
SELECT sub_one AS (
SELECT 'one' AS type,
COUNT(CASE WHEN a_q = 'GOOD' THEN 1) a_good,
COUNT(CASE WHEN a_q = 'OK' THEN 1) a_ok,
COUNT(CASE WHEN a_q = 'BAD' THEN 1) a_bad,
...
COUNT(CASE WHEN z_q = 'GOOD' THEN 1) z_good,
COUNT(CASE WHEN z_q = 'OK' THEN 1) z_ok,
COUNT(CASE WHEN z_q = 'BAD' THEN 1) z_bad,
FROM sub_base
WHERE type = 'one'
),
SELECT sub_two AS (
SELECT 'two' AS type,
COUNT(CASE WHEN a_q = 'GOOD' THEN 1) a_good,
COUNT(CASE WHEN a_q = 'OK' THEN 1) a_ok,
COUNT(CASE WHEN a_q = 'BAD' THEN 1) a_bad,
...
COUNT(CASE WHEN z_q = 'GOOD' THEN 1) z_good,
COUNT(CASE WHEN z_q = 'OK' THEN 1) z_ok,
COUNT(CASE WHEN z_q = 'BAD' THEN 1) z_bad,
FROM sub_base
WHERE type = 'two'
),
SELECT sub_all AS (
SELECT 'all' AS type,
COUNT(CASE WHEN a_q = 'GOOD' THEN 1) a_good,
COUNT(CASE WHEN a_q = 'OK' THEN 1) a_ok,
COUNT(CASE WHEN a_q = 'BAD' THEN 1) a_bad,
...
COUNT(CASE WHEN z_q = 'GOOD' THEN 1) z_good,
COUNT(CASE WHEN z_q = 'OK' THEN 1) z_ok,
COUNT(CASE WHEN z_q = 'BAD' THEN 1) z_bad,
FROM sub_base
)
SELECT * FROM sub_one
UNION
SELECT * FROM sub_two
UNION
SELECT * FROM sub_all
我想重用sub_one, sub_two, sub_all
中的子查询,因为除了SELECT和WHERE条件中的type
外,它们几乎相同。
如何避免将这些子查询复制粘贴?
答案 0 :(得分:2)
为什么不使用第二个CTE?
WITH sub_base AS (
...
),
second_cte AS (
SELECT
type,
COUNT(CASE WHEN a_q = 'GOOD' THEN 1) a_good,
COUNT(CASE WHEN a_q = 'OK' THEN 1) a_ok,
COUNT(CASE WHEN a_q = 'BAD' THEN 1) a_bad,
...
COUNT(CASE WHEN z_q = 'GOOD' THEN 1) z_good,
COUNT(CASE WHEN z_q = 'OK' THEN 1) z_ok,
COUNT(CASE WHEN z_q = 'BAD' THEN 1) z_bad
FROM sub_base
)
SELECT
*
FROM second_cte
WHERE type = 'one'
UNION
SELECT
*
FROM second_cte
WHERE type = 'two'
UNION
SELECT
*
FROM second_cte
WHERE type = 'all'
在这种情况下,您甚至不需要两个CTE,因为您不会重复使用第一个。因此,您可以将其放入子查询中:
WITH cte AS (
SELECT
type,
COUNT(CASE WHEN a_q = 'GOOD' THEN 1) a_good,
COUNT(CASE WHEN a_q = 'OK' THEN 1) a_ok,
COUNT(CASE WHEN a_q = 'BAD' THEN 1) a_bad,
...
COUNT(CASE WHEN z_q = 'GOOD' THEN 1) z_good,
COUNT(CASE WHEN z_q = 'OK' THEN 1) z_ok,
COUNT(CASE WHEN z_q = 'BAD' THEN 1) z_bad
FROM (
SELECT
<your sub_base query here>
) s
)
SELECT
*
FROM second_cte
WHERE type = 'one'
UNION
SELECT
*
FROM second_cte
WHERE type = 'two'
UNION
SELECT
*
FROM second_cte
WHERE type = 'all'
答案 1 :(得分:2)
使用GROUP BY
:
SELECT type,
COUNT(CASE WHEN a_q = 'GOOD' THEN 1) as a_good,
COUNT(CASE WHEN a_q = 'OK' THEN 1) as a_ok,
COUNT(CASE WHEN a_q = 'BAD' THEN 1) as a_bad,
...
COUNT(CASE WHEN z_q = 'GOOD' THEN 1) as z_good,
COUNT(CASE WHEN z_q = 'OK' THEN 1) as z_ok,
COUNT(CASE WHEN z_q = 'BAD' THEN 1) as z_bad,
FROM sub_base
WHERE type IN ('one', 'two', 'three') -- may not be needed
GROUP BY type;
在Postgres中,我将进一步简化它。您可以使用FILTER
或对二进制值求和:
SELECT type,
SUM( (a_q = 'GOOD')::int ) as a_good,
SUM( (a_q = 'OK')::int ) as a_ok,
SUM( (a_q = 'BAD')::int ) as a_bad,
...
SUM( (z_q = 'GOOD')::int ) as z_good,
SUM( (z_q = 'OK')::int ) as z_ok,
SUM( (z_q = 'BAD')::int ) as z_bad,
FROM sub_base
WHERE type IN ('one', 'two', 'three') -- may not be needed
GROUP BY type;
我也省去了CTE,只是将逻辑直接放在外部查询中,但这更多的是样式问题。
编辑:
您可以使用其他CTE:
WITH . . . ,
t as (
SELECT type,
SUM( (a_q = 'GOOD')::int ) as a_good,
SUM( (a_q = 'OK')::int ) as a_ok,
SUM( (a_q = 'BAD')::int ) as a_bad,
...
SUM( (z_q = 'GOOD')::int ) as z_good,
SUM( (z_q = 'OK')::int ) as z_ok,
SUM( (z_q = 'BAD')::int ) as z_bad,
FROM sub_base
WHERE type IN ('one', 'two', 'three') -- may not be needed
GROUP BY type
)
SELECT t.*
FROM t
UNION ALL
SELECT 'Total', SUM(a_good), SUM(a_ok), SUM(a_bad), . . .
FROM t;