【问题标题】:SQL grouping and running total of open items for a date rangeSQL 分组和运行日期范围内未清项的总计
【发布时间】:2011-07-13 01:31:58
【问题描述】:

为了简单起见,我有一个项目表,其中包含 ItemIDStartDateEndDate 项目列表。

ItemID     StartDate     EndDate
1          1/1/2011      1/15/2011
2          1/2/2011      1/14/2011
3          1/5/2011      1/17/2011
...

我的目标是能够将此表连接到具有顺序日期列表的表中, 并说出在特定日期有多少项目是打开的,以及有多少项目是累积打开的。

Date      ItemsOpened     CumulativeItemsOpen
1/1/2011  1               1
1/2/2011  1               2
...

我可以看到如何使用WHILE 循环来完成此操作, 但这会影响性能。我想知道如何 这可以通过基于集合的方法来完成吗?

【问题讨论】:

  • 您能否重新定义 ItemsOpened 和 ItemsOpenedCumulative 的含义?您接受的答案表明 ItemsOpened =“在此日期打开的项目数”和 ItemsOPenedCumulative =“当前打开的项目数”。如果答案不正确,我想删除我的答案
  • 好点;我的专栏命名留下了混乱的空间。 “当前打开的项目数”是我正在寻找的。​​span>
  • 您指的是 Cumulative 列还是 ItemsOpened 列?谢谢
  • 最后一件事,“ItemsOpened”是指“ItemsOpenedOnThisDay”吗?谢谢!
  • 是的,“ItemsOpened”的意思是“ItemsOpenedOnThisDay”。

标签: sql sql-server tsql stored-procedures


【解决方案1】:
SELECT COUNT(CASE WHEN d.CheckDate = i.StartDate THEN 1 ELSE NULL END)
         AS ItemsOpened
     , COUNT(i.StartDate)
         AS ItemsOpenedCumulative
FROM Dates AS d
  LEFT JOIN Items AS i
    ON d.CheckDate BETWEEN i.StartDate AND i.EndDate
GROUP BY d.CheckDate

【讨论】:

    【解决方案2】:

    这可能会给你想要的东西

    SELECT DATE, 
        SUM(ItemOpened) AS ItemsOpened, 
        COUNT(StartDate) AS ItemsOpenedCumulative
    FROM
        (
        SELECT d.Date, i.startdate, i.enddate,
            CASE WHEN i.StartDate = d.Date THEN 1 ELSE 0 END AS ItemOpened
        FROM Dates d
        LEFT OUTER JOIN Items i ON d.Date BETWEEN i.StartDate AND i.EndDate
        ) AS x
    GROUP BY DATE
    ORDER BY DATE
    

    这假定您的日期值是 DATE 数据类型。或者,日期是没有时间值的 DATETIME。

    【讨论】:

      【解决方案3】:

      您可能会发现这很有用。递归部分可以用一张桌子代替。为了证明它有效,我必须填充某种日期表。可以看到,实际的sql很短很简单。

      DECLARE @i table (itemid INT, startdate DATE, enddate DATE)
      
      INSERT @i VALUES (1,'1/1/2011', '1/15/2011') 
      INSERT @i VALUES (2,'1/2/2011', '1/14/2011')
      INSERT @i VALUES (3,'1/5/2011', '1/17/2011') 
      
      DECLARE @from DATE
      DECLARE @to DATE
      SET @from = '1/1/2011'
      SET @to = '1/18/2011'
      
      -- the recusive sql is strictly to make a datelist between @from and @to
      ;WITH cte(Date) 
      AS ( 
      SELECT @from DATE 
      UNION ALL 
      SELECT DATEADD(day, 1, DATE) 
      FROM cte ch     
      WHERE DATE < @to 
      ) 
      SELECT cte.Date, sum(case when cte.Date=i.startdate then 1 else 0 end) ItemsOpened, count(i.itemid) ItemsOpenedCumulative 
      FROM cte 
      left join @i i on cte.Date between i.startdate and i.enddate
      GROUP BY cte.Date
      OPTION( MAXRECURSION 0)
      

      【讨论】:

        【解决方案4】:

        如果您使用的是 SQL Server 2005+,则可以使用 recursive CTE 来获取运行总计,并借助 ranking 函数 ROW_NUMBER() 的额外帮助,如下所示:

        WITH grouped AS (
          SELECT
            d.Date,
            ItemsOpened = COUNT(i.ItemID),
            rn = ROW_NUMBER() OVER (ORDER BY d.Date)
          FROM Dates d
            LEFT JOIN Items i ON d.Date BETWEEN i.StartDate AND i.EndDate
          GROUP BY d.Date
          WHERE d.Date BETWEEN @FilterStartDate AND @FilterEndDate
        ),
        cumulative AS (
          SELECT
            Date,
            ItemsOpened,
            ItemsOpenedCumulative = ItemsOpened
          FROM grouped
          WHERE rn = 1
          UNION ALL
          SELECT
            g.Date,
            g.ItemsOpened,
            ItemsOpenedCumulative = g.ItemsOpenedCumulative + c.ItemsOpened
          FROM grouped g
            INNER JOIN cumulative c ON g.Date = DATEADD(day, 1, c.Date)
        )
        SELECT *
        FROM cumulative
        

        【讨论】:

        • 我相信上面有语法错误。 “WITH 累积 AS”应该只是“累积 AS”
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-05
        • 2013-01-07
        • 2018-04-13
        • 1970-01-01
        • 2023-03-11
        • 1970-01-01
        • 2012-01-28
        相关资源
        最近更新 更多