如何在 SQL 服务器中获取值为 0 的缺失日期?
How to get missing dates with 0 value in SQL Server?
我在 SQL 服务器中使用以下查询来查找 distinct
最近 7 天(不包括今天的日期)的登录次数:
SELECT TOP (7) CONVERT(date, LoginTime) AS ActivityDate, COUNT(DISTINCT LoginID) AS UserCount
FROM Login
WHERE CONVERT(date, LoginTime) < CONVERT(date, GETDATE())
GROUP BY CONVERT(date, LoginTime)
ORDER BY ActivityDate DESC;
它生成以下输出:
ActivityDate | UserCount
----------------------
2019-02-21 | 2
2019-02-20 | 3
2019-02-19 | 2
2019-02-15 | 2
2019-02-14 | 1
2019-02-13 | 2
2019-02-12 | 3
我的期望是按顺序排列所有最后 7 天(不像当前输出那样 2019-02-16
、2019-02-17
和 2019-02-18
在 2019-02-19
之后丢失).我需要它,如果缺少日期,则必须以 0 计数显示它。
我的预期输出如下:
ActivityDate | UserCount
----------------------
2019-02-21 | 2
2019-02-20 | 3
2019-02-19 | 2
2019-02-18 | 0
2019-02-17 | 0
2019-02-16 | 0
2019-02-15 | 2
你可以试试这个。在这里您需要获得第一个最小日期和最大日期。之后,您需要生成这两天之间的所有日期。最后你需要同时加入 table.
declare @MinDate date
declare @MaxDate date
select * into #temp from(
select top (7) CONVERT(date,LoginTime) as ActivityDate,count(distinct LoginID) as UserCount
from Login
where CONVERT(date,LoginTime )< convert(date,getdate())
group by CONVERT(date,LoginTime )
order by ActivityDate desc;
)a
Set @MinDate = (select min (ActivityDate) from #temp)
Set @MaxDate = (select max (ActivityDate) from #temp)
Select a.Date, isnull(b.UserCount,0) as UserCount from(
SELECT TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, @MinDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;
)a left join #temp b on a.Date = b.ActivityDate
您可以找到现场演示 Here。我已将您的查询输出插入临时 table 但逻辑相同。
要查看特定值,该值必须来自一行。因此,要查看登录 table 中不存在的日期,您必须在 某处 .
中生成它们作为行
您可以使用简单的递归 CTE 在特定时间间隔内每天生成 1 行,然后使用 LEFT JOIN
加入在该特定日期匹配的登录。不匹配的仍然会显示,因为我们使用的是 LEFT JOIN
.
DECLARE @GeneratingDateFrom DATE = DATEADD(DAY, -7, GETDATE())
DECLARE @GeneratingDateTo DATE = GETDATE()
;WITH GeneratedDates AS
(
SELECT
GeneratedDate = @GeneratingDateFrom
UNION ALL
SELECT
GeneratedDate = DATEADD(DAY, 1, G.GeneratedDate)
FROM
GeneratedDates AS G
WHERE
DATEADD(DAY, 1, G.GeneratedDate) < @GeneratingDateTo
)
SELECT
G.GeneratedDate,
count(distinct L.LoginID) as UserCount
FROM
GeneratedDates AS G
LEFT JOIN [Login] AS L ON G.GeneratedDate = CONVERT(date, L.LoginTime)
GROUP BY
G.GeneratedDate
ORDER BY
G.GeneratedDate desc
只有 7 天,所以只需输入这些日期:
SELECT ActivityDate, COUNT(DISTINCT LoginID) AS UserCount
FROM (VALUES
(CAST(CURRENT_TIMESTAMP - 1 AS DATE)), -- build the list of dates
(CAST(CURRENT_TIMESTAMP - 2 AS DATE)),
(CAST(CURRENT_TIMESTAMP - 3 AS DATE)),
(CAST(CURRENT_TIMESTAMP - 4 AS DATE)),
(CAST(CURRENT_TIMESTAMP - 5 AS DATE)),
(CAST(CURRENT_TIMESTAMP - 6 AS DATE)),
(CAST(CURRENT_TIMESTAMP - 7 AS DATE))
) datelist(ActivityDate)
LEFT JOIN Login ON CAST(LoginTime AS DATE) = ActivityDate
GROUP BY ActivityDate
ORDER BY ActivityDate DESC
生成 table 中没有行的日期以加入 calendar table 的最佳方法。
这是一个非常简单的日历 table 一年,基于 this answer:
CREATE TABLE [Calendar]
(
[CalendarDate] DATETIME
)
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = GETDATE()
SET @EndDate = DATEADD(d, 365, @StartDate)
WHILE @StartDate <= @EndDate
BEGIN
INSERT INTO [Calendar]
(
CalendarDate
)
SELECT
@StartDate
SET @StartDate = DATEADD(dd, 1, @StartDate)
END
(您可以修改此查询以在将来添加更多日期,以便暂时不需要维护它。)
现在您可以像这样在查询中加入日历 table:
select top (7) c.CalendarDate as ActivityDate,count(distinct LoginID) as UserCount
from Calendar c
left join Login l
ON c.CalendarDate = CONVERT(date, l.LoginTime)
and CONVERT(date,LoginTime )< convert(date,getdate())
group by c.CalendarDate
order by c.CalendarDate desc;
值得 space 它占用,它也会在许多其他情况下派上用场。
我在 SQL 服务器中使用以下查询来查找 distinct
最近 7 天(不包括今天的日期)的登录次数:
SELECT TOP (7) CONVERT(date, LoginTime) AS ActivityDate, COUNT(DISTINCT LoginID) AS UserCount
FROM Login
WHERE CONVERT(date, LoginTime) < CONVERT(date, GETDATE())
GROUP BY CONVERT(date, LoginTime)
ORDER BY ActivityDate DESC;
它生成以下输出:
ActivityDate | UserCount
----------------------
2019-02-21 | 2
2019-02-20 | 3
2019-02-19 | 2
2019-02-15 | 2
2019-02-14 | 1
2019-02-13 | 2
2019-02-12 | 3
我的期望是按顺序排列所有最后 7 天(不像当前输出那样 2019-02-16
、2019-02-17
和 2019-02-18
在 2019-02-19
之后丢失).我需要它,如果缺少日期,则必须以 0 计数显示它。
我的预期输出如下:
ActivityDate | UserCount
----------------------
2019-02-21 | 2
2019-02-20 | 3
2019-02-19 | 2
2019-02-18 | 0
2019-02-17 | 0
2019-02-16 | 0
2019-02-15 | 2
你可以试试这个。在这里您需要获得第一个最小日期和最大日期。之后,您需要生成这两天之间的所有日期。最后你需要同时加入 table.
declare @MinDate date
declare @MaxDate date
select * into #temp from(
select top (7) CONVERT(date,LoginTime) as ActivityDate,count(distinct LoginID) as UserCount
from Login
where CONVERT(date,LoginTime )< convert(date,getdate())
group by CONVERT(date,LoginTime )
order by ActivityDate desc;
)a
Set @MinDate = (select min (ActivityDate) from #temp)
Set @MaxDate = (select max (ActivityDate) from #temp)
Select a.Date, isnull(b.UserCount,0) as UserCount from(
SELECT TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, @MinDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;
)a left join #temp b on a.Date = b.ActivityDate
您可以找到现场演示 Here。我已将您的查询输出插入临时 table 但逻辑相同。
要查看特定值,该值必须来自一行。因此,要查看登录 table 中不存在的日期,您必须在 某处 .
中生成它们作为行您可以使用简单的递归 CTE 在特定时间间隔内每天生成 1 行,然后使用 LEFT JOIN
加入在该特定日期匹配的登录。不匹配的仍然会显示,因为我们使用的是 LEFT JOIN
.
DECLARE @GeneratingDateFrom DATE = DATEADD(DAY, -7, GETDATE())
DECLARE @GeneratingDateTo DATE = GETDATE()
;WITH GeneratedDates AS
(
SELECT
GeneratedDate = @GeneratingDateFrom
UNION ALL
SELECT
GeneratedDate = DATEADD(DAY, 1, G.GeneratedDate)
FROM
GeneratedDates AS G
WHERE
DATEADD(DAY, 1, G.GeneratedDate) < @GeneratingDateTo
)
SELECT
G.GeneratedDate,
count(distinct L.LoginID) as UserCount
FROM
GeneratedDates AS G
LEFT JOIN [Login] AS L ON G.GeneratedDate = CONVERT(date, L.LoginTime)
GROUP BY
G.GeneratedDate
ORDER BY
G.GeneratedDate desc
只有 7 天,所以只需输入这些日期:
SELECT ActivityDate, COUNT(DISTINCT LoginID) AS UserCount
FROM (VALUES
(CAST(CURRENT_TIMESTAMP - 1 AS DATE)), -- build the list of dates
(CAST(CURRENT_TIMESTAMP - 2 AS DATE)),
(CAST(CURRENT_TIMESTAMP - 3 AS DATE)),
(CAST(CURRENT_TIMESTAMP - 4 AS DATE)),
(CAST(CURRENT_TIMESTAMP - 5 AS DATE)),
(CAST(CURRENT_TIMESTAMP - 6 AS DATE)),
(CAST(CURRENT_TIMESTAMP - 7 AS DATE))
) datelist(ActivityDate)
LEFT JOIN Login ON CAST(LoginTime AS DATE) = ActivityDate
GROUP BY ActivityDate
ORDER BY ActivityDate DESC
生成 table 中没有行的日期以加入 calendar table 的最佳方法。
这是一个非常简单的日历 table 一年,基于 this answer:
CREATE TABLE [Calendar]
(
[CalendarDate] DATETIME
)
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = GETDATE()
SET @EndDate = DATEADD(d, 365, @StartDate)
WHILE @StartDate <= @EndDate
BEGIN
INSERT INTO [Calendar]
(
CalendarDate
)
SELECT
@StartDate
SET @StartDate = DATEADD(dd, 1, @StartDate)
END
(您可以修改此查询以在将来添加更多日期,以便暂时不需要维护它。)
现在您可以像这样在查询中加入日历 table:
select top (7) c.CalendarDate as ActivityDate,count(distinct LoginID) as UserCount
from Calendar c
left join Login l
ON c.CalendarDate = CONVERT(date, l.LoginTime)
and CONVERT(date,LoginTime )< convert(date,getdate())
group by c.CalendarDate
order by c.CalendarDate desc;
值得 space 它占用,它也会在许多其他情况下派上用场。