按类型对计数进行分组时使用哪个 SQL 范例?

Which SQL paradigm to use when grouping counts by type?

假设我有一个数据库,其中包含来自一家披萨店的数据。我通过两个 table 跟踪客户和他们的订单:customerordersorderscustomer 的 FK,这样我就可以很容易地看到哪些订单属于哪个客户。

我可以这样计算客户的所有订单:

SELECT
    c.id,
    COUNT(o.id) AS order_counts
FROM
    customers AS c,
    JOIN orders ON c.id = o.customer_id
GROUP BY
    c.id

这给了我这样的东西:

results = [
{
  “customer_number”: 1,
  “order_counts”: 5
},
{
  “customer_number”: 2,
  “order_counts”: 10
}]

但是,如果我想“分解”order_counts 结果以显示所有单独的披萨类型,然后计算这些类型怎么办?我会添加一个名为 pizzas 的新 table,它有一个 name 列,然后让我的结果如下所示:

results = [
{
  “customer_number”: 1,
  “counts”: {
    “Hawaiian”: 2,
    “Meat Lovers”: 2,
    "Four Cheese": 1
  }
},
{
  “customer_number”: 2,
  “counts”: {
    “Hawaiian”: 5,
    “Meat Lovers”: 5,
    "Four Cheese": 0
  }
}]

我需要利用哪个 SQL principals/paradigms 来实现这一目标?我怀疑我需要一个子查询 and/or 一个嵌套的 GROUP BY 语句。

额外问题:这在 Django ORM 中是否可行,或者这是否会很快达到 ORM 的限制?

生成的结果可能包含多个客户 ID,但这些数字是特定于比萨饼的。

SELECT
    c.id,
    COUNT(o.id) AS order_counts,
    p.name
FROM
    customers AS c,
    JOIN orders o ON c.id = o.customer_id
    JOIN pizzas p ON p.id = o.pizzas_id
GROUP BY
    c.id,
    p.name

如果你真的想要那种嵌套输出,那么你不妨直接从数据库生成JSON:

select
    c.id customer_id,
    sum(no_pizzas) no_orders,
    jsonb_object_agg(p.name, o.cnt_pizza) counts
from customers AS c,
inner join (
    select customer_id, pizza_id, count(*) cnt_pizza
    from orders o 
    group by customer_id, pizza_id 
) o on c.id = o.customer_id
inner join pizza p  on p.id = o.pizza_id
group by c.id

这会将列 counts 生成为 json 对象,其中比萨名称作为键,比萨计数作为值。作为奖励,您仍然可以在 no_orders.

列中获得订单总数

如果您想考虑没有订单的客户,请使用 left joins:

select
    c.id customer_id,
    coalesce(sum(no_pizzas), 0) no_orders,
    jsonb_object_agg(p.name, o.cnt_pizza) counts
from customers AS c,
left join (
    select customer_id, pizza_id, count(*) cnt_pizza
    from orders o 
    group by customer_id, pizza_id 
) o on c.id = o.customer_id
left join pizza p  on p.id = o.pizza_id
group by c.id