You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多表关联查询问题:按州统计指定日期销售总额

多表关联聚合查询:按州统计指定日期销售总额

需求

按州统计2020-01-01和2021-01-01的销售总额,并显示州名。

表结构与测试数据

CREATE TABLE IF NOT EXISTS estado (
    id SERIAL PRIMARY KEY,
    estado VARCHAR(100) -- 州名
)

CREATE TABLE IF NOT EXISTS municipio (
    id SERIAL PRIMARY KEY,
    estado integer REFERENCES estado(id), -- 关联州ID
    municipio VARCHAR(100) -- 城市名
)

CREATE TABLE IF NOT EXISTS vendas (
    id SERIAL PRIMARY KEY,
    municipio integer REFERENCES municipio(id), -- 关联城市ID
    valor numeric, -- 销售金额
    data_venda date -- 销售日期
)

-- 插入测试数据
INSERT INTO estado VALUES (1, 'PR');
INSERT INTO estado VALUES (2, 'SC');
INSERT INTO estado VALUES (3, 'RS');
INSERT INTO municipio VALUES (1, 1, 'Pelotas');
INSERT INTO municipio VALUES (2, 1, 'Caxias do Sul');
INSERT INTO municipio VALUES (3, 1, 'Porto Alegre');
INSERT INTO municipio VALUES (4, 2, 'Florianopolis');
INSERT INTO municipio VALUES (5, 2, 'Chapeco');
INSERT INTO municipio VALUES (6, 2, 'Itajai');
INSERT INTO municipio VALUES (7, 3, 'Curitiba');
INSERT INTO municipio VALUES (8, 3, 'Maringa');
INSERT INTO municipio VALUES (9, 3, 'Foz do Iguaçu');
INSERT INTO vendas VALUES (1, 6, 5, '2020-01-01');
INSERT INTO vendas VALUES (2, 5, 10, '2021-01-01');
INSERT INTO vendas VALUES (3, 5, 5, '2020-01-01');
INSERT INTO vendas VALUES (4, 4, 2, '2020-01-01');
INSERT INTO vendas VALUES (5, 3, 10, '2021-01-01');
INSERT INTO vendas VALUES (6, 3, 12, '2020-01-01');
INSERT INTO vendas VALUES (7, 3, 20, '2020-01-01');
INSERT INTO vendas VALUES (8, 2, 10, '2020-01-01');
INSERT INTO vendas VALUES (9, 1, 11, '2021-01-01');
INSERT INTO vendas VALUES (10, 9, 4, '2020-01-01');

原查询的问题

SELECT 
    e.estado, SUM(v.valor) as sum2021, SUM(v2.valor) as sum2020
FROM vendas v 
    CROSS JOIN vendas v2 
    INNER JOIN municipio m ON v.municipio = m.id
    INNER JOIN estado e ON m.estado = e.id
WHERE v.data_venda = '2021-01-01' 
    AND v2.data_venda = '2020-01-01' 
GROUP BY 1;
  • 数值异常原因:CROSS JOIN vendas v2会让2021年的每条销售记录与2020年的每条销售记录进行笛卡尔积配对,导致SUM计算时重复累加,最终金额被放大。
  • RS州未显示原因:INNER JOIN配合WHERE条件同时要求存在2021和2020年的销售数据,而RS州只有2020年的销售记录,因此被过滤,无法出现在结果中。

正确查询方案

方案一:条件聚合(推荐)

通过CASE语句在同一聚合中分别统计两个日期的销售额,同时用LEFT JOIN保证所有州都被展示:

SELECT 
    e.estado,
    -- 统计2021-01-01的销售总额,无数据则为0
    SUM(CASE WHEN v.data_venda = '2021-01-01' THEN v.valor ELSE 0 END) AS sum2021,
    -- 统计2020-01-01的销售总额,无数据则为0
    SUM(CASE WHEN v.data_venda = '2020-01-01' THEN v.valor ELSE 0 END) AS sum2020
FROM estado e
LEFT JOIN municipio m ON e.id = m.estado
LEFT JOIN vendas v ON m.id = v.municipio 
    AND v.data_venda IN ('2020-01-01', '2021-01-01') -- 提前过滤目标日期,减少计算量
GROUP BY e.estado;

方案二:子查询关联

分别统计两个日期的州级销售总额,再通过LEFT JOIN关联到所有州,用COALESCE将NULL转为0:

SELECT 
    e.estado,
    COALESCE(s2021.total, 0) AS sum2021,
    COALESCE(s2020.total, 0) AS sum2020
FROM estado e
-- 关联2021年的销售统计
LEFT JOIN (
    SELECT 
        es.id,
        SUM(v.valor) AS total
    FROM vendas v
    JOIN municipio m ON v.municipio = m.id
    JOIN estado es ON m.estado = es.id
    WHERE v.data_venda = '2021-01-01'
    GROUP BY es.id
) s2021 ON e.id = s2021.id
-- 关联2020年的销售统计
LEFT JOIN (
    SELECT 
        es.id,
        SUM(v.valor) AS total
    FROM vendas v
    JOIN municipio m ON v.municipio = m.id
    JOIN estado es ON m.estado = es.id
    WHERE v.data_venda = '2020-01-01'
    GROUP BY es.id
) s2020 ON e.id = s2020.id;

内容的提问来源于stack exchange,提问作者Raffa Bass

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 23:45:34