我的SQL Server查询应该计算每个客户的订单数量,以及他们的奖励积分的SUM
。对于大多数客户而言,结果是准确的(大多数人只有一个或两个订单)。对于少数人来说,结果非常糟糕。
这是原始查询:
SELECT
c.email,
c.lastlogindate,
c.custenabled,
c.maillist,
d.GroupName,
COUNT(o.orderid) AS orders,
SUM(r.points) AS total_points
FROM
((customers c
LEFT JOIN orders o ON (c.contactid = o.ocustomerid AND o.ostep = 'step 5')
)
LEFT JOIN discount_group d ON c.discount = d.id
)
LEFT JOIN
customer_rewards r ON r.contactid = c.contactid
WHERE
c.last_update > '2014-02-01'
OR c.lastlogindate > '2014-02-01'
GROUP BY
c.email, c.custenabled, c.maillist, c.lastlogindate, d.GroupName;
例如,customerid 1234订购了21个订单,总计2724个点。这将报告他已经下了441个订单(21 * 21),价值57204点(2724 * 21)。原始数据很好,但是每个订单行都被它们下的订单量复制(但不是大多数客户......)
如果我将查询更改为:
SELECT
o.orderid,
c.email,
COUNT(o.orderid) AS orders,
SUM(r.points) AS total_points
FROM
((customers c
INNER JOIN orders o ON (c.contactid = o.ocustomerid AND o.ostep = 'step 5')
)
)
INNER JOIN
customer_rewards r ON r.contactid = c.contactid
WHERE
c.last_update > '2014-02-01'
OR c.lastlogindate > '2014-02-01'
GROUP BY
c.email, o.orderid;
聚合函数计算正确,但每个订单会显示一个结果。所以它将显示“客户1234/21订单/ 2724点”,21次。
我确实删除了第二个查询中的'discount_group'联接,但这只是为了让它更容易阅读和更改。这对结果没有任何影响。
答案 0 :(得分:1)
以下是使用常用表表达式聚合结果的解决方案。
注意:这不会显示有0个订单或0个奖励积分的客户。如果您想要显示这些内容,请将INNER JOIN
更改为LEFT JOIN
s
WITH cteOrders AS
(
SELECT o.ocustomerid, orderCount = count(*)
FROM orders o
WHERE o.ostep = 'step 5'
GROUP BY o.ocustomerid
)
, cteRewards as
(
SELECT cr.contactid, total_points = SUM(cr.points)
FROM customer_rewards cr
GROUP BY cr.contactid
)
SELECT
c.email,
o.orderCount as orders,
r.total_points
FROM
customers c
INNER JOIN cteOrders o ON c.contactid = o.ocustomerid
INNER JOIN cteRewards r ON r.contactid = c.contactid
WHERE
c.last_update > '2014-02-01'
OR c.lastlogindate > '2014-02-01'
;
或使用子查询:
SELECT
c.email,
o.orderCount as orders,
r.total_points
FROM
customers c
INNER JOIN
(
SELECT o.ocustomerid, orderCount = count(*)
FROM orders o
WHERE o.ostep = 'step 5'
GROUP BY o.ocustomerid
) o ON c.contactid = o.ocustomerid
INNER JOIN
(
SELECT cr.contactid, total_points = SUM(cr.points)
FROM customer_rewards cr
GROUP BY cr.contactid
) r ON r.contactid = c.contactid
WHERE
c.last_update > '2014-02-01'
OR c.lastlogindate > '2014-02-01'
;