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

PostgreSQL中按客户统计订单ID数量的异常问题排查

问题描述

我编写了如下PostgreSQL查询语句:

SELECT
    fato_pedido_promob.id_pedido_promob,
    dim_tempo.data,
    fato_pedido_promob.valor_total_pedido,
    dim_cliente_promob.cpf_cnpj,
    dim_cliente_promob.email,
    dim_cliente_promob.segmento,
    dim_cliente_promob.razao_social,
    data_ultimo_pedido,
    extract(day from current_date::timestamp - data_ultimo_pedido::timestamp) as dias_ultimo_pedido,
    count(fato_pedido_promob.id_pedido_promob) as pedidos_por_cpf
    
FROM
    dim_cliente_promob
LEFT JOIN
    fato_pedido_promob ON dim_cliente_promob.id_cliente = fato_pedido_promob.fk_cliente_promob
LEFT JOIN
            dim_tempo ON dim_tempo.id_tempo = fato_pedido_promob.fk_data_emissao
LEFT JOIN
    (
        SELECT
            cpf_cnpj,
            MAX(dim_tempo.data) AS data_ultimo_pedido
        FROM
            dim_cliente_promob
        LEFT JOIN
            fato_pedido_promob ON dim_cliente_promob.id_cliente = fato_pedido_promob.fk_cliente_promob
        LEFT JOIN
            dim_tempo ON dim_tempo.id_tempo = fato_pedido_promob.fk_data_emissao
        WHERE
            cpf_cnpj <> 'Desconhecido'
            AND id_pedido_promob IS NOT NULL
            AND dim_tempo.data < CURRENT_DATE
        GROUP BY
            cpf_cnpj
    ) AS max_data ON dim_cliente_promob.cpf_cnpj = max_data.cpf_cnpj
WHERE
    dim_cliente_promob.cpf_cnpj <> 'Desconhecido'
    AND id_pedido_promob IS NOT NULL
    AND data < CURRENT_DATE 
GROUP BY    
    dim_cliente_promob.cpf_cnpj,
    fato_pedido_promob.id_pedido_promob,
    dim_tempo.data,
    fato_pedido_promob.valor_total_pedido,
    dim_cliente_promob.email,
    dim_cliente_promob.segmento,
    dim_cliente_promob.razao_social,
    data_ultimo_pedido
ORDER BY
    data DESC;

其中客户ID为dim_cliente_promob.cpf_cnpj,订单ID为fato_pedido_promob.id_pedido_promob。我需要统计每个客户的订单ID数量,但使用count(fato_pedido_promob.id_pedido_promob) as pedidos_por_cpf时,所有客户的统计结果都返回1,请问问题出在哪里?

问题原因

问题出在GROUP BY子句的字段选择:你把唯一标识单个订单的fato_pedido_promob.id_pedido_promob加入了分组条件中。因为每个订单ID都是唯一的,所以每个分组只会包含该订单ID对应的一条记录,count()自然会返回1,无法实现按客户统计总订单数的需求。

解决方案

根据你的需求,有两种常见的修正方式:

方式一:使用窗口函数保留订单明细,同时统计客户总订单数

如果你需要保留每条订单的明细数据,同时在每行显示该客户的总订单数,可以用窗口函数COUNT() OVER (PARTITION BY ...)替代普通的聚合count():

SELECT
    fato_pedido_promob.id_pedido_promob,
    dim_tempo.data,
    fato_pedido_promob.valor_total_pedido,
    dim_cliente_promob.cpf_cnpj,
    dim_cliente_promob.email,
    dim_cliente_promob.segmento,
    dim_cliente_promob.razao_social,
    data_ultimo_pedido,
    extract(day from current_date::timestamp - data_ultimo_pedido::timestamp) as dias_ultimo_pedido,
    -- 用窗口函数按客户分组统计总订单数
    COUNT(fato_pedido_promob.id_pedido_promob) OVER (PARTITION BY dim_cliente_promob.cpf_cnpj) as pedidos_por_cpf
    
FROM
    dim_cliente_promob
LEFT JOIN
    fato_pedido_promob ON dim_cliente_promob.id_cliente = fato_pedido_promob.fk_cliente_promob
LEFT JOIN
            dim_tempo ON dim_tempo.id_tempo = fato_pedido_promob.fk_data_emissao
LEFT JOIN
    (
        SELECT
            cpf_cnpj,
            MAX(dim_tempo.data) AS data_ultimo_pedido
        FROM
            dim_cliente_promob
        LEFT JOIN
            fato_pedido_promob ON dim_cliente_promob.id_cliente = fato_pedido_promob.fk_cliente_promob
        LEFT JOIN
            dim_tempo ON dim_tempo.id_tempo = fato_pedido_promob.fk_data_emissao
        WHERE
            cpf_cnpj <> 'Desconhecido'
            AND id_pedido_promob IS NOT NULL
            AND dim_tempo.data < CURRENT_DATE
        GROUP BY
            cpf_cnpj
    ) AS max_data ON dim_cliente_promob.cpf_cnpj = max_data.cpf_cnpj
WHERE
    dim_cliente_promob.cpf_cnpj <> 'Desconhecido'
    AND id_pedido_promob IS NOT NULL
    AND data < CURRENT_DATE 
ORDER BY
    data DESC;

这种方式不需要修改GROUP BY,因为窗口函数是对结果集进行分组统计,不会改变原有的行结构。

方式二:调整GROUP BY字段,按客户维度聚合统计

如果你只需要按客户维度展示总订单数,不需要每条订单的明细,可以修改GROUP BY,只保留客户相关的分组字段,并对订单相关字段做聚合处理:

SELECT
    dim_cliente_promob.cpf_cnpj,
    dim_cliente_promob.email,
    dim_cliente_promob.segmento,
    dim_cliente_promob.razao_social,
    max_data.data_ultimo_pedido,
    extract(day from current_date::timestamp - max_data.data_ultimo_pedido::timestamp) as dias_ultimo_pedido,
    COUNT(fato_pedido_promob.id_pedido_promob) as pedidos_por_cpf,
    -- 如果需要订单相关的聚合值,比如总金额、最新订单日期等
    SUM(fato_pedido_promob.valor_total_pedido) as total_gasto,
    MAX(dim_tempo.data) as ultima_data_pedido
FROM
    dim_cliente_promob
LEFT JOIN
    fato_pedido_promob ON dim_cliente_promob.id_cliente = fato_pedido_promob.fk_cliente_promob
LEFT JOIN
            dim_tempo ON dim_tempo.id_tempo = fato_pedido_promob.fk_data_emissao
LEFT JOIN
    (
        SELECT
            cpf_cnpj,
            MAX(dim_tempo.data) AS data_ultimo_pedido
        FROM
            dim_cliente_promob
        LEFT JOIN
            fato_pedido_promob ON dim_cliente_promob.id_cliente = fato_pedido_promob.fk_cliente_promob
        LEFT JOIN
            dim_tempo ON dim_tempo.id_tempo = fato_pedido_promob.fk_data_emissao
        WHERE
            cpf_cnpj <> 'Desconhecido'
            AND id_pedido_promob IS NOT NULL
            AND dim_tempo.data < CURRENT_DATE
        GROUP BY
            cpf_cnpj
    ) AS max_data ON dim_cliente_promob.cpf_cnpj = max_data.cpf_cnpj
WHERE
    dim_cliente_promob.cpf_cnpj <> 'Desconhecido'
    AND id_pedido_promob IS NOT NULL
    AND dim_tempo.data < CURRENT_DATE 
GROUP BY    
    dim_cliente_promob.cpf_cnpj,
    dim_cliente_promob.email,
    dim_cliente_promob.segmento,
    dim_cliente_promob.razao_social,
    max_data.data_ultimo_pedido
ORDER BY
    max_data.data_ultimo_pedido DESC;

这种方式会将同一客户的所有订单合并为一行,展示该客户的总订单数及其他聚合信息。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 11:22:24