对于 SQL 来说相对较新,我对这个小问题感到困惑。这似乎并不难做到,但我似乎无法弄清楚。
我正在尝试从表中获取交易计数,但我似乎无法让 SQL 显示所有月份,而不仅仅是交易发生的月份和年份。
这是查询:
SELECT YEAR(dbo.countproject.trans_date) AS [TransYear]
, MONTH (dbo.countproject.trans_date) AS [TransMonth]
, COUNT(Id) AS TransNum
FROM dbo.countproject
WHERE dbo.countproject.make_name = 'Honda'
AND dbo.countproject.model_name = 'Civic'
AND dbo.countproject.type = 'Sale'
AND dbo.countproject.trans_type LIKE '%%EU'
AND dbo.countproject.mfr = '2000'
GROUP BY YEAR(dbo.countproject.trans_date)
, MONTH(dbo.countproject.trans_date)
ORDER BY YEAR(dbo.countproject.trans_date)
查询返回以下结果集:
| TransYear | TransMonth | TransNum |
|-----------|------------|----------|
| 2004 | 1 | 5 |
| 2004 | 3 | 1 |
| 2005 | 4 | 2 |
等等......
我试图让它显示所有月份和年份,即使该值为 NULL。
我尝试创建一个新表,其中包含年份和月份作为列,以使其以某种方式加入,但我迷失了。
如有任何帮助,我们将不胜感激。
最佳答案
如果您使用的是SQL Server 2005 或更高版本
,您可以使用公用表表达式(CTE)
来获得所需的结果。下面的示例显示了如何获取问题中描述的结果。
Click here to view the demo in SQL Fiddle.
描述:
- Create 和 insert 语句创建表并填充一些示例数据。我根据问题中提供的查询创建了表格。
- WITH 子句中的语句正在执行递归表达式。在本例中,
UNION ALL
上方的SELECT
会获取表 dbo.countproject 中可用的最小和最大日期
- 获取最小日期后,UNION ALL 之后的第二个 SELECT 语句将以 1 个月的间隔递增日期,直到递归表达式达到表中可用的最大日期。
- 递归 CTE 已生成所有可能的可用日期。此输出可在名为 alltransactions 的表中找到。
- 我们必须使用
LEFT OUTER JOIN
将此 CTE 输出alltransactions
与实际表countproject
连接起来,因为我们想要显示所有年份和月份即使没有交易。 - 表
alltransactions
和countproject
在日期的年 和月 部分连接。然后,查询在 WHERE 子句中应用必要的过滤器,然后按年和月对数据进行分组,然后再按年和月进行排序。 - 从示例数据中您可以注意到,表中最早的日期为
2004-07-01
,最新日期为2005-12-01
。因此,输出显示从 2004 年/月 07 到 2005 年/月 12。
希望有帮助。
脚本:
CREATE TABLE dbo.countproject
(
id INT NOT NULL IDENTITY
, trans_date DATETIME NOT NULL
, make_name VARCHAR(20) NOT NULL
, model_name VARCHAR(20) NOT NULL
, type VARCHAR(20) NOT NULL
, trans_type VARCHAR(20) NOT NULL
, mfr INT NOT NULL
);
INSERT INTO dbo.countproject (trans_date, make_name, model_name, type, trans_type, mfr) VALUES
('1900-01-01', 'Honda', 'Civic', 'Sale', 'EU', 2000),
('1900-01-01', 'Toyota', 'Corolla', 'Sale', 'EU', 2000),
('2004-07-01', 'Nissan', 'Altima', 'Sale', 'EU', 2000),
('2005-12-01', 'Toyota', 'Camry', 'Sale', 'EU', 2000),
('2004-04-01', 'Ford', 'Focus', 'Sale', 'EU', 2000),
('2005-08-01', 'Honda', 'Civic', 'Sale', 'EU', 2000),
('2005-11-01', 'Toyota', 'Camry', 'Sale', 'EU', 2000),
('2004-08-01', 'Toyota', 'Corolla', 'Sale', 'EU', 2000),
('2005-12-01', 'Honda', 'Civic', 'Sale', 'EU', 2000),
('2004-07-01', 'Honda', 'Civic', 'Sale', 'EU', 2000),
('2004-11-01', 'Honda', 'Civic', 'Sale', 'EU', 2000),
('2005-08-01', 'Honda', 'Civic', 'Sale', 'EU', 2000);
;WITH alltransactions
AS
(
SELECT MIN(trans_date) AS continuousdate
, MAX(trans_date) AS maximumdate
FROM dbo.countproject
WHERE trans_date <> '1900-01-01'
UNION ALL
SELECT DATEADD(MONTH, 1, continuousdate) AS continuousdate
, maximumdate
FROM alltransactions
WHERE DATEADD(MONTH, 1, continuousdate) <= maximumdate
)
SELECT YEAR(at.continuousdate) AS [Year]
, MONTH(at.continuousdate) AS [Month]
, COUNT(cp.trans_date) AS [Count]
FROM alltransactions at
LEFT OUTER JOIN countproject cp
ON YEAR(at.continuousdate) = YEAR(cp.trans_date)
AND MONTH(at.continuousdate) = MONTH(cp.trans_date)
AND cp.make_name = 'Honda'
and cp.model_name = 'Civic'
and cp.type = 'Sale'
and cp.trans_type LIKE '%EU'
and cp.mfr = '2000'
GROUP BY YEAR(at.continuousdate)
, MONTH(at.continuousdate)
ORDER BY [Year]
, [Month];
输出:
Year Month Count
----- ------ -----
2004 4 0
2004 5 0
2004 6 0
2004 7 1
2004 8 0
2004 9 0
2004 10 0
2004 11 1
2004 12 0
2005 1 0
2005 2 0
2005 3 0
2005 4 1
2005 5 0
2005 6 0
2005 7 0
2005 8 2
2005 9 0
2005 10 0
2005 11 0
2005 12 1
关于sql - 如何获取按月和年分组的数据(包括没有数据的时期)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10389915/