我正在使用SQL Server查询这三个看起来像的表(有一些额外的列但不相关):
我想得到每周的总销售额和客户数(同时显示地址详情)。我已经提出了这个问题
mysql> DESCRIBE `maillog`;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| Id | varchar(200) | NO | PRI | Test | |
| email | varchar(255) | YES | MUL | NULL | |
+-------+--------------+------+-----+---------+-------+
即使我的SQL技能几乎没有,它看起来像是在做它的工作。但是现在我希望每当一个客户没有特定周的销售(周数只是整数)时就能显示0。我想知道我是否应该在Sales表中获得周数的不同值,然后循环它们(不确定如何)
任何帮助?
由于
答案 0 :(得分:2)
使用CROSS JOIN
为所有客户和周生成行。然后使用LEFT JOIN
引入可用的数据:
SELECT c.Name, a.Street, a.StreetNo, w.Week,
COALESCE(SUM(s.Total), 0) as Total
FROM Customers c CROSS JOIN
(SELECT DISTINCT s.Week FROM sales s) w LEFT JOIN
Addresses a
ON c.CustomerId = a.CustomerId LEFT JOIN
Sales s
ON s.week = w.week AND s.AddressId = a.AddressId
GROUP BY c.Name, a.Street, a.StreetNo, w.Week;
使用表别名很好,但别名应该是表名的缩写。因此,a
Addresses
而非Customers
。
答案 1 :(得分:1)
请尝试以下方法......
SELECT Name,
Street,
StreetNo,
Week,
SUM( CASE
WHEN Total IS NULL THEN
0
ELSE
Total
END ) AS Total
FROM Customers a
JOIN Addresses b ON a.Id = b.CustomerId
RIGHT JOIN Sales c ON b.Id = c.AddressId
GROUP BY a.Name,
c.Week,
b.Street,
b.StreetNo;
我已经在三个地方修改了你的陈述。首先是我将您的加入更改为Sales
到RIGHT JOIN
。这将与INNER JOIN
一样加入,但它也会保留JOIN
的右侧侧的表中没有匹配记录的记录或左侧的记录组,将NULL
值放在结果数据集的字段中,这些字段来自JOIN
的左侧。 LEFT JOIN
的工作方式相同,但 left 表格中的任何额外记录都会被保留。
我已从您幸存的INNER
中移除了INNER JOIN
这个词。如果JOIN
前面没有连接类型,则会执行INNER JOIN
。 JOIN
和INNER JOIN
都被认为是正确的,但主流协议似乎是将INNER
保留在外,RDBMS允许将其遗漏(SQL-Server会这样做)。您使用的仍然完全取决于您 - 我已将其留在此处以用于说明目的。
第三个更改是我添加了一个CASE
语句,用于测试Total
字段是否包含NULL
值,如果该客户没有销售,则会显示该值那个星期。如果是,则SUM()
会返回NULL
,因此CASE
语句会返回0
。如果Total
不包含NULL
值,则会执行该分组的所有SUM()
值Total
。
请注意,我假设Total
除了NULL
之外不会有任何RIGHT JOIN
个值。如果这个假设不正确,请告诉我。
另请注意,我假设Week
表格中的Customer
不会丢失Sales
,或者如果有True
表单您不想列出它们。如果这个假设不正确,请再次告诉我。
如果您有任何问题或意见,请随时发表评论。
答案 2 :(得分:1)
您应该生成周数,而不是使用DISTINCT
。这在性能和可靠性方面更好。然后在Sales表上使用LEFT JOIN
而不是INNER JOIN
:
SELECT a.Name
,b.Street
,b.StreetNo
,weeks.[Week]
,COALESCE(SUM(c.Total),0) as Total
FROM Customers a
INNER JOIN Addresses b ON a.Id = b.CustomerId
CROSS JOIN (
-- Generate a sequence of 52 integers (13 x 4)
SELECT ROW_NUMBER() OVER (ORDER BY a.x) AS [Week]
FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) a(x)
CROSS JOIN (SELECT x FROM (VALUES(1),(1),(1),(1)) b(x)) b
) weeks
LEFT JOIN Sales c ON b.Id = c.AddressId AND c.[Week] = weeek.[Week]
GROUP BY a.Name
,b.Street
,b.StreetNo
,weeks.[Week]