如何在查询中转义多个with?

How to escape several with in the query?

我需要重构我的查询,但我不知道该怎么做。

我可以看到几个重复使用相同的逻辑,但我不断重复这种查询方式,一个查询一个查询,我觉得,这种查询成为我的主要思维框架SQL 我不想要这个。

你能告诉我这个查询的更可接受的变体吗,这样我就不会再重复我的想法了?

在这里

WITH fourth_table AS
(
    WITH third_table AS
    (
        WITH second_table AS
        (
            WITH initial_table AS
            (
                SELECT 
                DISTINCT ctr.country_region, EXTRACT (YEAR FROM s.time_id)::int AS calendar_year, chn.channel_desc, 
                SUM(s.amount_sold) OVER (PARTITION BY ctr.country_region||chn.channel_desc||EXTRACT (YEAR FROM s.time_id)) AS amount_sold
                FROM sales s
                JOIN channels chn ON s.channel_id = chn.channel_id
                JOIN customers c ON s.cust_id  = c.cust_id
                JOIN countries ctr ON c.country_id = ctr.country_id
                WHERE ctr.country_region IN ('Americas','Asia', 'Europe')
                AND
                EXTRACT (YEAR FROM s.time_id)::int IN (1998, 1999, 2000, 2001)
                ORDER BY ctr.country_region, calendar_year, chn.channel_desc
            )
                SELECT country_region, calendar_year, channel_desc, amount_sold,
                (amount_sold/SUM(amount_sold) OVER (PARTITION BY country_region||calendar_year)*100)::decimal(10,2) AS bychannels
                FROM initial_table
        )
        SELECT *,
        LAG (bychannels, 4) OVER (ORDER BY 6) AS lower_salary
        FROM second_table--correct here smth wrong
    )
    SELECT *, bychannels - lower_salary AS diff FROM third_table
)
SELECT country_region, calendar_year, channel_desc, 
--'FM     999,999,999,990D'
LPAD(to_char(amount_sold, 'FM999,999,999,990 $'),20, ' ') AS amount_sold,
LPAD(bychannels || ' %' ,20, ' ') AS "% BY CHANNELS",
LPAD(lower_salary || ' %    ' ,20, ' ') AS "% PREVIOUS PERIOD", 
diff AS "% DIFF"
FROM fourth_table WHERE calendar_year NOT IN (1998);

您将 CTE(通用 Table 查询)与子查询混合使用,with 子句的优点通常在于可读性:

with initial_table as
(
    SELECT 
    DISTINCT ctr.country_region, EXTRACT (YEAR FROM s.time_id)::int AS calendar_year, chn.channel_desc, 
    SUM(s.amount_sold) OVER (PARTITION BY ctr.country_region||chn.channel_desc||EXTRACT (YEAR FROM s.time_id)) AS amount_sold
    FROM sales s
    JOIN channels chn ON s.channel_id = chn.channel_id
    JOIN customers c ON s.cust_id  = c.cust_id
    JOIN countries ctr ON c.country_id = ctr.country_id
    WHERE ctr.country_region IN ('Americas','Asia', 'Europe')
    AND
    EXTRACT (YEAR FROM s.time_id)::int IN (1998, 1999, 2000, 2001)
    ORDER BY ctr.country_region, calendar_year, chn.channel_desc
)
,second_table as
(
    SELECT country_region, calendar_year, channel_desc, amount_sold,
    (amount_sold/SUM(amount_sold) OVER (PARTITION BY country_region||calendar_year)*100)::decimal(10,2) AS bychannels
    FROM initial_table
)
,third_table as
(
    SELECT *,
    LAG (bychannels, 4) OVER (ORDER BY 6) AS lower_salary
    FROM second_table--correct here smth wrong
)
,fourth_table as
(
    SELECT *, bychannels - lower_salary AS diff FROM third_table
)
SELECT country_region, calendar_year, channel_desc, 
--'FM     999,999,999,990D'
LPAD(to_char(amount_sold, 'FM999,999,999,990 $'),20, ' ') AS amount_sold,
LPAD(bychannels || ' %' ,20, ' ') AS "% BY CHANNELS",
LPAD(lower_salary || ' %    ' ,20, ' ') AS "% PREVIOUS PERIOD", 
diff AS "% DIFF"
FROM fourth_table WHERE calendar_year NOT IN (1998);