在 PostgreSQL 中连接多个 table,并计算连接的 table 行

Joining multiple tables in PostgreSQL, and counting joined table rows

我有三个 table。我正在尝试查询我的 PRICE_LIST table,并计算每个价目表中有价格的 SKU 数量,以及分配给每个价目表的客户数量。

表格

我的PRICE_LISTtable:

price_list_id
price_number
name

这个table有41行。

我的SKU_PRICEtable:

sku_id
price_number

这个 table 有 1,132 行。

我的CUSTOMERtable:

customer_id
price_number
customer_type
is_active

这个 table 有 6,535 行,但我只想要活跃的 "E" 类型的客户,所以我想要的行数减少到 2,961。

查询

我的查询:

SELECT
  pl.price_list_id,
  pl.price_number,
  pl.name,
  count(sp.sku_id)     "sku_count",
  count(c.customer_id) "customer_count"
FROM price_list pl
  LEFT JOIN sku_price sp ON (sp.price_number = pl.price_number)
  LEFT JOIN customer c ON (c.price_number = pl.price_number)
WHERE c.customer_type = 'E' AND c.is_active = 'T'
GROUP BY pl.price_list_id, pl.price_number, pl.name;

问题

我遇到的问题是结果太疯狂了:

 price_list_id | price_number | name  | sku_count | customer_count
---------------+--------------+-------+-----------+----------------
            31 |            4 | SF0   |         0 |            792
            33 |            6 | SF2   |     30525 |          30525
             2 |            2 | ASNP2 |       972 |            972
             1 |            1 | ASNP1 |      1596 |           1596
            34 |            7 | SF3   |       616 |            616
            37 |           10 | SF6   |         0 |             51
            32 |            5 | SF1   |      1144 |           1144

我得到的 SKU 计数和客户计数均为 30,525,这一事实告诉我连接正在做一些奇怪的事情。我也不明白为什么我没有得到没有产品也没有客户的价目表(而且有很多)。

如果我将 PRICE_LIST 加入到一个 table — SKU_PRICECUSTOMER — 我会得到合理的结果。只有当我尝试同时执行这两项操作时,它才会崩溃。

如果有人能在正确的方向上推动我,我将不胜感激。

FWIW,我在 OS X 上使用 PostgreSQL 9.3.5。

如果我理解你的模式,你可以做类似的事情

select
    pl.price_list_id,
    pl.price_number,
    pl.name,
    count(distinct sp.sku_id) as "sku_count",
    count(distinct c.customer_id) as "customer_count"
from price_list pl
    left outer join sku_price as sp on sp.price_number = pl.price_number
    left outer join customer as c on c.price_number = pl.price_number
where c.customer_type = 'E' and c.is_active = 'T'
group by pl.price_list_id, pl.price_number, pl.name;

但在性能方面我认为这样做会更好:

with cte_sku_price as (
     select count(*) as cnt, price_number from sku_price group by price_number
), cte_customer as (
     select count(*) as cnt, price_number
     from customer
     where customer_type = 'E' and is_active = 'T'
     group by price_number
)
select
    pl.price_list_id,
    pl.price_number,
    pl.name,
    sp.cnt as "sku_count",
    c.cnt as "customer_count"
from price_list pl
    left outer join cte_customer as c on c.price_number = pl.price_number
    left outer join cte_sku_price as sp on sp.price_number = pl.price_number