SQL Server SQL日历和值计数

oymdgrw7  于 2023-02-03  发布在  其他
关注(0)|答案(2)|浏览(150)

SQL管理工作室18
我有一个多列的表,我需要的列是值,打开日期,关闭日期。
我需要计算案件的日历日期,#案件打开,#案件关闭和净。案件不打开和关闭每天,因此日历需要考虑到这一点。
示例数据
| 价值|开启日期|关闭日期|
| - ------|- ------|- ------|
| 小行星123456|2023年1月26日00时00分00秒|2023年1月31日00时00分00秒|
| 小行星653421|2023年2月1日00时00分00秒|2023年2月2日00:00:0000|
| 小行星987654|2023年2月1日00时00分00秒|零|
预期结果
| 日历日期|打开计数|关闭计数|净额|
| - ------|- ------|- ------|- ------|
| 2023年1月26日|1个|无|1个|
| 2023年1月27日|无|无|1个|
| 2023年1月28日|无|无|1个|
| 2023年1月29日|无|无|1个|
| 2023年1月30日|无|无|1个|
| 2023年1月31日|无|1个|无|
| 二○二三年二月一日|第二章|无|第二章|
| 二○二三年二月二日|无|1个|1个|

57hvy0tb

57hvy0tb1#

这是一个很常见的问题。完美的解决方案是在数据库/服务器中添加一个日历表,但这并不总是可行的。你可以使用一个CTE技巧来模拟一个基本的问题,该技巧利用了数据中实际存在的范围:

;WITH BaseDates AS (
SELECT MIN(DateOpen) AS Date, CASE WHEN MAX(DateClosed)>MAX(DateOpen) THEN MAX(DateClosed) ELSE MAX(DateOpen) END AS mDate
  FROM @Example
UNION ALL
SELECT DATEADD(DAY,1,Date), mDate
  FROM BaseDates
 WHERE date < mDate
)

| 日期|m日期|
| - ------|- ------|
| 2023年1月26日|二○二三年二月二日|
| 2023年1月27日|二○二三年二月二日|
| 2023年1月28日|二○二三年二月二日|
| 2023年1月29日|二○二三年二月二日|
| 2023年1月30日|二○二三年二月二日|
| 2023年1月31日|二○二三年二月二日|
| 二○二三年二月一日|二○二三年二月二日|
| 二○二三年二月二日|二○二三年二月二日|
这为我们提供了数据范围内所有日期的完整列表。然后,我们可以将其用作初始表进行查询,以获得所需的结果:

;WITH BaseDates AS (
SELECT MIN(DateOpen) AS Date, CASE WHEN MAX(DateClosed)>MAX(DateOpen) THEN MAX(DateClosed) ELSE MAX(DateOpen) END AS mDate
  FROM @Example
UNION ALL
SELECT DATEADD(DAY,1,Date), mDate
  FROM BaseDates
 WHERE date < mDate
)

SELECT Date, OpenCnt, ClosedCnt, SUM(OpenCnt-ClosedCnt) OVER (ORDER BY Date) AS NetCnt
  FROM (
SELECT Date, COUNT(DISTINCT o.Value) AS OpenCnt, COUNT(DISTINCT c.Value) AS ClosedCnt
  FROM BaseDates b
    LEFT OUTER JOIN @Example o
      ON b.Date = o.DateOpen
      AND (
               b.date < o.DateClosed 
            OR o.DateClosed IS NULL
          )
    LEFT OUTER JOIN @Example c
      ON b.Date = c.DateClosed
 GROUP BY b.Date
       ) a

在这里,我们使用baseDates,并对当天的open和closed数据进行左外连接,计算不同值列的数量,将其用作子查询,并在顶部应用窗口求和函数,以获得按日期排序的运行总数。
| 日期|开放计数|关闭计数|净计数|
| - ------|- ------|- ------|- ------|
| 2023年1月26日|1个|无|1个|
| 2023年1月27日|无|无|1个|
| 2023年1月28日|无|无|1个|
| 2023年1月29日|无|无|1个|
| 2023年1月30日|无|无|1个|
| 2023年1月31日|无|1个|无|
| 二○二三年二月一日|第二章|无|第二章|
| 二○二三年二月二日|无|1个|1个|

x4shl7ld

x4shl7ld2#

这是另一个使用特别的计数/数字表和条件聚合的选项。最后,窗口函数sum() over()计算运行的NET。
你可能注意到我在数字表中使用了TOP 1000。请随意调整到一个更合理的数字(* 但要慷慨...留一些回旋余地 *)

    • 示例**
;with cte as (
Select CalendarDate  
      ,CountOpen    = sum( case when [DateOpen]  =CalendarDate then 1 else 0 end)
      ,CountClosed  = sum( case when [DateClosed]=CalendarDate then 1 else 0 end)
 From YourTable
 Join ( Select Top 1000 N=-1+Row_Number() Over (Order By (Select NULL)) From master..spt_values n1, master..spt_values n2 ) B
   on N<=datediff(day,[DateOpen],coalesce([DateClosed],[DateOpen]))
 Cross Apply ( values (dateadd(day,N,[DateOpen])) ) C(CalendarDate)
 Group By CalendarDate
)
Select *
      ,Net = sum(CountOpen-CountClosed) over (order by CalendarDate)
 From  cte
 Order by CalendarDate
    • 结果**

相关问题