我正试图(让我们说)收集一份关于客户的报告。在该报告中,我想要包括每个客户的订单总数和票号。
表:
Customer(id, name)
Order(id, customer_id, amount)
support_ticket(id, customer_id)
查询:
select
c.id as 'Customer',
count(distinct t.id) as "Ticket count",
count(distinct o.id) as "Order count",
sum(o.amount) as 'Order Amount'
from customer as c
inner join `order` as o on c.id = o.customer_id
inner join support_ticket as t on c.id = t.customer_id
group by c.id
因为我在两个表上加入customer.id,所以我得到所有行“重复”,因为我得到了所有可能的组合,所以如果客户端作为多个票据,sum(o.amount)
将因为“重复行”而成倍增加
sqlFiddle(mysql):http://sqlfiddle.com/#!9/ba39ba/13
sqlFiddle(pg):http://sqlfiddle.com/#!17/bc32e/7
这似乎是一个简单的案例,但我一直在考虑太多,我认为,我找不到正确的方法来做那个报告。
我究竟做错了什么?
您最好的选择是将Order表中的聚合重写为派生表;
例如
select
c.id as 'Customer',
count(distinct t.id) as "Ticket count",
o.amount as 'Order Amount' ,
o.[Order count]
from customer as c
inner join
(SELECT
o.customer_id,
sum(amount) as amount ,
count(distinct o.id) as "Order count"
from [order]
group by o.customer_id)
as o on c.id = o.customer_id
inner join support_ticket as t on c.id = t.customer_id
group by
c.id ,
o.amount ,
o.[Order count]
请注意,派生表列随后会添加到底部的group by子句中。
干杯!
只需在子查询中计算order
值并加入即可。
SELECT
c.id as 'Customer'
,count(DISTINCT st.id) as 'Ticket Count'
,o.`Order Count`
,o.amount as `Order Amount`
FROM customer c
INNER JOIN support_ticket st
on c.id = st.customer_id
INNER JOIN (
SELECT
customer_id
,SUM(amount) as 'amount'
,count(distinct id) as 'Order Count'
FROM `order`
group by customer_id
) o
on c.id = o.customer_id
GROUP BY c.id;
select c.id as 'Customer'
,t2.count_ticket as "Ticket count"
,t1.count_order as "Order count"
,t1.amount as 'Order Amount'
from customer as c
inner join (select customer_id
,count(id) as count_order
,sum(amount) as amount
from Order group by customer_id) t1
on c.id = t1.customer_id
inner join (select customer_id
,count(id) as count_ticket
from support_ticket group by customer_id) t2
on c.id = t2.customer_id
在像你这样的情况下,当我认为我的问题的解决方案应该相当简单但我无法绕过它时,我倾向于使用WITH
条款。
不是因为它更好,而是因为它通过分解复杂性帮助我更好地理解我的代码。首先,我创建一个相对简单的临时。解决我问题的第一部分。
WITH temp AS (
SELECT
c.id AS "customer",
COUNT(DISTINCT o.id) AS "order_count",
SUM(o.amount) AS "order_amount"
FROM customer AS c
INNER JOIN "order" AS o on c.id = o.customer_id
GROUP BY c.id
)
然后我只需从temp中选择我的解决方案的前半部分,以这种方式添加所有中间结果,并解决我的初始sql的第二部分。
SELECT
temp.customer,
COUNT(DISTINCT t.id) as "ticket_count",
temp.order_count,
temp.order_amount
FROM temp
INNER JOIN support_ticket as t on temp.customer = t.customer_id
GROUP BY temp.customer, temp.order_count, temp.order_amount
原理与之前的所有答案一样,但SELECTS
是分开的,我可以快速检查它们,如果我对解决方案的某些部分感到满意,继续。