如何推断 SQL Server 中的日期以计算每日计数?

Posted

技术标签:

【中文标题】如何推断 SQL Server 中的日期以计算每日计数?【英文标题】:How to extrapolate dates in SQL Server to calculate the daily counts? 【发布时间】:2021-11-23 19:56:48 【问题描述】:

这就是数据的样子。这是一张长桌

我需要计算每天雇用的人数

如何编写 SQL Server 逻辑来得到这个结果?我想创建一个 DATES 表然后加入,但这会导致错误,因为表太大。我需要递归逻辑吗?

【问题讨论】:

根据问题指南,请不要发布代码、数据、错误消息等的图像 - 将文本复制或输入到问题中。请保留将图像用于图表或演示渲染错误,无法通过文本准确描述的事情。 根据问题指南,请展示您的尝试并告诉我们您发现了什么(在本网站或其他地方)以及为什么它不能满足您的需求。 你遇到了什么错误?日历表应该可以完美运行。 以下任何答案对您有帮助吗? 【参考方案1】:

对于未来的问题,请勿发布数据图片。相反,请使用dbfiddle 之类的服务。无论如何,我会为答案添加一个草图,如果你有一个准备得更好的问题,你可能会得到一个完整的答案。无论如何它都在这里:

-- extrema is the least and the greatest date in staff table
with extrema(mn, mx) as (
    select least(min(hired),min(retired)) as mn
         , greatest(max(hired),max(retired)) as mx
    from staff
), calendar (dt) as (
    -- we construct a calendar with every date between extreme values
    select mn from extrema
    union all
    select dateadd(day, 1, d)
    from calendar
    where dt < (select mx from extrema)
)
-- finally we can count the number of employed people for each such date
select dt, count(1) 
from calendar c 
join staff s
    on c.dt between s.hired and s.retired
group by dt; 

如果您发现自己经常进行此类计算,最好创建一个日历表。您可以为其添加其他属性,例如它是否是一周中的某一天等。

约束为:

CHECK(hired <= retired)

第一部分可以简化为:

with extrema(mn, mx) as (
    select min(hired) as mn
         , max(retired) as mx
    from staff
),

【讨论】:

【参考方案2】:

假设当前员工的退休日期为 NULL

Declare @Date1 date = '2015-01-01'
Declare @Date2 date = getdate()

Select A.Date
      ,HeadCount = count(B.name)
 From ( Select Top (DateDiff(DAY,@Date1,@Date2)+1) 
               Date=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),@Date1) 
         From  master..spt_values n1,master..spt_values n2
      ) A
 Left Join YourTable B on A.Date >= B.Hired and A.Date <= coalesce(B.Retired,getdate())
 Group BY A.Date

【讨论】:

【参考方案3】:

为此您需要一个日历表。您从日历开始,然后使用BETWEEN 逻辑左连接其他所有内容。

您可以使用真实的桌子。或者您可以即时生成它,如下所示:

WITH
    L0 AS ( SELECT c = 1
            FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),
                        (1),(1),(1),(1),(1),(1),(1),(1)) AS D(c) ),
    L1 AS ( SELECT c = 1 FROM L0 A, L0 B, L0 C, L0 D ),
    Nums AS ( SELECT rownum = ROW_NUMBER() OVER(ORDER BY (SELECT 1))
              FROM L1 ),
    Dates AS (
      SELECT TOP (DATEDIFF(day, '20141231', GETDATE()))
        Date = DATEADD(day, rownum, '20141231')
      FROM Nums
    )

SELECT
  d.Date,
  NumEmployed = COUNT(*)
FROM Dates d
JOIN YourTable t ON d.Date BETWEEN t.Hired AND t.Retired
GROUP BY
  d.Date;

如果您的日期有时间组件,那么您需要使用 &gt;= AND &lt; 逻辑

【讨论】:

【参考方案4】:

尝试限制日期表的范围。在此示例中,我有一个名为 TallyStickDT 的日期表。

SELECT dt, COUNT(name)
FROM (
    SELECT dt
    FROM tallystickdt
    WHERE dt >= (SELECT MIN(hired) FROM #employees)
    AND dt <= GETDATE()
) A
LEFT OUTER JOIN #employees E ON A.dt >= E.Hired AND A.dt <= e.retired
GROUP BY dt
ORDER BY dt

【讨论】:

以上是关于如何推断 SQL Server 中的日期以计算每日计数?的主要内容,如果未能解决你的问题,请参考以下文章

您如何在 SQL Server 中计算每天计划中的任务数?

如何根据日期对SQL Server中的多个列进行排序

SQL Server:计算组中的不同日期

SQL Server - 以 HH:MM:SS 格式计算两个日期时间戳之间的经过时间

在 SQL Server 2008 中计算到期日期

SQL sever 2008 如何根据一个表中的两个时间计算出时间差