【问题标题】:SQL - Count total bugs open per daySQL - 计算每天打开的错误总数
【发布时间】:2014-07-09 13:59:03
【问题描述】:

我需要制作一个表格,其中包含从 01/01/2012 到现在的每个日期的一行,并计算每个日期当前打开的错误数量。

这是我在名为 Bugs 的表中拥有的数据:BugIDCreatedDateUpdatedDateStatus(状态可以是打开或关闭)。如果 bug 已关闭,那么 UpdatedDate 就是它关闭的日期。如果 bug 是开放的,那么 UpdatedDate 是无关紧要的,因为 bug 开放到当前日期。

我可以列出日期,但我不知道从那里做什么。

WITH D AS ( SELECT @RangeStartDate DateValue UNION ALL SELECT DateValue + 1 FROM D
WHERE DateValue + 1 < @RangeEndDate ),

【问题讨论】:

  • 使用 D 作为主表 LEFT join to bugs on createDate>= D.DateValue AND (D.DateValue
  • 是否有理由不将它放在行而不是列中,例如日期列和错误计数列,每天有行?
  • @xQbert 您是否建议在此之前使用 SELECT 语句?
  • 下面的答案示例虽然有几个不错的选择。
  • 您将从计数或数字表中获得更好的性能,而不是使用递归 cte。你所拥有的基本上是一个隐藏的循环。

标签: sql sql-server


【解决方案1】:
WITH D AS
 (
  SELECT @RangeStartDate DateValue
  UNION ALL
  SELECT DateValue + 1
  FROM D

  WHERE DateValue + 1 < @RangeEndDate
 )
Select D.DateValue, coalesce(count(BugID),0)
FROM D
LEFT JOIN Bugs B 
  on B.CreateDate <= D.Datevalue
 and (B.UpdateDate >= D.DateValue or B.UpdateDate is null)
Group By D.DateValue

意图:返回 d 中的所有日期,并且只返回那些与 bug 匹配的记录 如果错误创建日期小于日期,错误大于更新日期,或者如果更新日期为空。

【讨论】:

  • 我想你忘了把条件放在括号里的or 附近,这将返回不正确的结果。
【解决方案2】:
declare @bugs table(BUGID int,Createddate datetime,Updateddate datetime,Status char(1))
insert into @bugs
Select 1,'20140101',NULL,'I'
UNION Select 2,'20140102','20140110','U'
UNION Select 3,'20140103','20140110','C'
UNION Select 4,'20140104',NULL,'I'
UNION Select 5,'20140105','20140110','U'
UNION Select 6,'20140106','20140109','C'
UNION Select 10,'20140101','20140110','C'

declare @RangeStartDate datetime
declare @RangeEndDate datetime
select @RangeStartDate ='20140101'
select @RangeEndDate ='20140201'

;WITH D AS
 (
  SELECT @RangeStartDate DateValue
  UNION ALL
  SELECT DateValue + 1
  FROM D
  WHERE DateValue + 1 < @RangeEndDate
 )
Select D.* ,
(Select SUM(dd) from
(Select 1 as DD from @bugs b where  b.Createddate<=d.DateValue and ((b.Status<>'C')  or (b.Status='C' and b.Updateddate>=d.DateValue)) ) a) 
from D

【讨论】:

    【解决方案3】:

    我认为您可以使用以下查询

    ;WITH D AS
     (
      SELECT @RangeStartDate DateValue
      UNION ALL
      SELECT DateValue + 1
      FROM D
      WHERE DateValue + 1 < @RangeEndDate
     )
     SELECT D.DateValue, COUNT(ISNULL(BugID,0))
     FROM D LEFT JOIN Bugs ON D.DateValue >= Bugs.CreatedDate 
        AND (D.DateValue <= Bugs.UpdatedDate OR Bugs.UpdatedDate IS NULL)
     GROUP BY D.DateValue
    

    【讨论】:

      【解决方案4】:

      从您的 CTE 日期开始,我会使用这样的查询(当错误仍然存​​在时,我认为 UpdatedDate = NULL):

      WITH D AS
       (
        SELECT @RangeStartDate DateValue
        UNION ALL
        SELECT DateValue + 1
        FROM D
      
        WHERE DateValue + 1 < @RangeEndDate
       ),
      SELECT D.DateValue,
             (SELECT COUNT(*)
              FROM Bugs
              WHERE CreatedDate <= D.DateValue
                AND (UpdatedDate > D.DateValue
                     OR UpdatedDate IS NULL)) AS NumberOfBugs
      FROM D
      

      【讨论】:

        【解决方案5】:

        CTE 中,您应该使用适当的函数来操作日期,例如DATEADD,以使代码在数据类型更改为DateTime2 时继续工作。

        代码非常简单:选择一个日期,获取在该日期之前带有CreatedDate 的所有错误,然后计算日期在 UpdateDate 之后的错误,以及日期之前的错误UpdateDate 以获取仍处于打开状态的错误。

        状态字段并不是真正需要的,因为错误的状态是通过 UpdateDate 不是NULL 来确定的。

        DECLARE @RangeStartDate datetime2 = '20120201'
        DECLARE @RangeEndDate datetime2 = '20120228'
        
        ;WITH D AS (
          SELECT @RangeStartDate DateValue
          UNION ALL
          SELECT DATEADD(d, 1, DateValue)
          FROM   D
          WHERE  DATEADD(d, 1, DateValue) <= @RangeEndDate
        )
        SELECT DateValue
             , BugsOpen = COUNT(CASE WHEN DateValue < COALESCE(UpdatedDate, '99991231') 
                                     THEN 1 
                                     ELSE NULL 
                                END)
             , BugsClose = COUNT(CASE WHEN DateValue >= COALESCE(UpdatedDate, '99991231')
                                      THEN 1 
                                      ELSE NULL 
                                 END)
        FROM   D
               LEFT JOIN Bugs ON DateValue >= CreatedDate
        GROUP BY DateValue
        

        SQLFiddle demo

        【讨论】:

          【解决方案6】:

          虽然至少有几个已经发布的答案似乎有效,但它们都继续使用递归 cte 进行计数。这与使用 while 循环相同。它非常慢。我强烈建议对这类事情使用数字/计数表。它会快很多。我在此处实现它的方式导致 0 次读取以生成包含 10,000 行的表。

          if OBJECT_ID('tempdb..#Bugs') is not null
              drop table #Bugs
          
          create table #Bugs
          (
              BugID int identity not null primary key clustered, 
              BugName varchar(10) not null,
              CreatedDate datetime not null default getdate(), 
              UpdatedDate datetime null, 
              IsClosed bit not null default 0
          )
          
          insert #Bugs(BugName, CreatedDate, UpdatedDate)
          select 'Bug 1', GETDATE(), null union all
          select 'Bug 2', GETDATE() - 3, null union all
          select 'Bug 3', GETDATE() -5, GETDATE() -3 union all
          select 'Bug 4', getdate()-8, GETDATE() - 7
          
          select * from #Bugs
          
          declare @RangeStart datetime = getdate() - 10;
          
          WITH
              E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
              E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
              E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
              cteTally(N) AS 
              (
                  SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
              )
          select DATEADD(day, N, @RangeStart), *
          from cteTally t
          cross apply
          (
              select COUNT(*) as OpenBugCount
              from #Bugs
              where CreatedDate <= DATEADD(day, N, @RangeStart)
                  AND (UpdatedDate >= DATEADD(day, N, @RangeStart) OR UpdatedDate is null)
          ) b
          where t.N <= DATEDIFF(day, @RangeStart, getdate());
          

          看看这种计数方式与 rCTE 的执行计划。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-06-24
            • 1970-01-01
            • 1970-01-01
            • 2019-03-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多