从表中计算当前连续天数

时间:2013-07-30 19:13:27

标签: sql sql-server sql-server-2000

我有一个似乎是常见的业务请求,但我找不到明确的解决方案。我有一个每日报告(在众多报告中)根据失败的标准生成并保存到表中。每个报告都有一个与其绑定的类型ID,以表示它是哪个报告,并且有一个导入事件ID表示导入的日期(添加日期列以进行额外说明)。我添加了一个sqlfiddle来查看表的基本架构(为隐私问题重命名)。

http://www.sqlfiddle.com/#!3/81945/8

当前生成的所有报告都运行正常,因此无需在表格中修改任何内容。但是,对于一份报告(类型11),我不仅需要提取今天出现的发票,还需要添加一列,总计该发票的运行日期(包括当天)的连续天数。根据提供的模式,结果应如下所示:

INVOICE     MESSAGE     EVENT_DATE      CONSECUTIVE_DAYS_ON_REPORT
12345       Yes         July, 30 2013    6
54355       Yes         July, 30 2013    2
644644      Yes         July, 30 2013    4

我只需要连续最近几天,而不是任何可能出现的其他日子。我试图运行自联接无济于事,我的最后一次尝试也被列为sqlfiddle文件的一部分,但无济于事。有什么建议或想法吗?我现在很困惑。

仅供参考:我在SQL Server 2000中工作!我在2005年和2008年看到过很多巧妙的技巧,但我无法访问它们。

非常感谢您的帮助!

3 个答案:

答案 0 :(得分:0)

我不久前有一个类似的要求获得排名前五的连续数量的“前5名”排名。我找到的唯一解决方案是在游标中进行。光标有一个date = @daybefore,如果你的数据不匹配则在光标内部退出循环,否则设置@daybefore = datediff(dd, -1, @daybefore)。

如果您想要一个例子,请告诉我。似乎有很多爱好者,即使他们没有更好的解决方案,他们在看到“光标”这个词的时候就会击退...

在这里,尝试这样的标量函数:

CREATE FUNCTION ConsequtiveDays
(
    @invoice bigint, @date datetime
)
RETURNS int
AS
BEGIN
    DECLARE @ct int = 0, @Count_Date datetime, @Last_Date datetime

    SELECT @Last_Date = @date

    DECLARE counter CURSOR LOCAL FAST_FORWARD
    FOR
    SELECT event_date FROM tblEventInfo 
    WHERE invoice = @invoice
    ORDER BY event_date DESC

    FETCH NEXT FROM counter
    INTO @Count_Date

    WHILE @@FETCH_STATUS = 0 AND DATEDIFF(dd,@Last_Date,@Count_Date) < 2
    BEGIN
        @ct = @ct + 1
    END

    CLOSE counter
    DEALLOCATE counter

    RETURN @ct

END
GO

答案 1 :(得分:0)

这样的东西? http://www.sqlfiddle.com/#!3/81945/14

SELECT
  [final].*,
  [last].total_rows
FROM
  tblEventInfo   AS [final]
INNER JOIN
(
  SELECT
    [first_of_last].type_id,
    [first_of_last].invoice,
    MAX([all_of_last].event_date)   AS event_date,
    COUNT(*)                        AS total_rows
  FROM
  (
    SELECT
      [current].type_id,
      [current].invoice,
      MAX([current].event_date)   AS event_date
    FROM
      tblEventInfo   AS [current]
    LEFT JOIN
      tblEventInfo   AS [previous]
        ON  [previous].type_id    = [current].type_id
        AND [previous].invoice    = [current].invoice
        AND [previous].event_date = [current].event_date-1
    WHERE
          [current].type_id = 11
      AND [previous].type_id IS NULL
    GROUP BY
      [current].type_id,
      [current].invoice
  )
    AS [first_of_last]
  INNER JOIN
    tblEventInfo  AS [all_of_last]
      ON  [all_of_last].type_id     = [first_of_last].type_id
      AND [all_of_last].invoice     = [first_of_last].invoice
      AND [all_of_last].event_date >= [first_of_last].event_date
  GROUP BY
    [first_of_last].type_id,
    [first_of_last].invoice
)
  AS [last]
    ON  [last].type_id    = [final].type_id
    AND [last].invoice    = [final].invoice
    AND [last].event_date = [final].event_date

最内层查询查找最后一个连续记录块的起始记录。

然后连接到该连续记录块中的所有记录,给出最终日期和行数(连续几天)

然后加入到最后一天的行来获取消息,等等。


确保您实际上在(type_id, invoice, event_date)上有索引。

答案 2 :(得分:0)

你有多个问题。分开处理它们并建立起来。

<强>问题:

1)识别连续范围:从范围列中减去row_number,并按结果

分组

2)SQL 2000中没有ROW_NUMBER()函数:使用相关子查询伪造它。

3)您实际上想要DENSE_RANK()而不是ROW_NUMBER:首先列出唯一日期。

<强>解决方案:

3)

SELECT MAX(id) AS id,invoice,event_date FROM tblEventInfo GROUP BY invoice,event_date

2)

  SELECT t2.invoice,t2.event_date,t2.id,
    DATEDIFF(day,(SELECT COUNT(DISTINCT event_date) FROM (SELECT MAX(id) AS id,invoice,event_date FROM tblEventInfo GROUP BY invoice,event_date) t1 WHERE t2.invoice = t1.invoice AND t2.event_date > t1.event_date),t2.event_date) grp
  FROM (SELECT MAX(id) AS id,invoice,event_date FROM tblEventInfo GROUP BY invoice,event_date) t2
  ORDER BY invoice,grp,event_date

1)

SELECT
  t3.invoice AS INVOICE,
  MAX(t3.event_date) AS EVENT_DATE,
  COUNT(t3.event_date) AS CONSECUTIVE_DAYS_ON_REPORT
FROM (
  SELECT t2.invoice,t2.event_date,t2.id,
    DATEDIFF(day,(SELECT COUNT(DISTINCT event_date) FROM (SELECT MAX(id) AS id,invoice,event_date FROM tblEventInfo GROUP BY invoice,event_date) t1 WHERE t2.invoice = t1.invoice AND t2.id > t1.id),t2.event_date) grp
  FROM (SELECT MAX(id) AS id,invoice,event_date FROM tblEventInfo GROUP BY invoice,event_date) t2
) t3
GROUP BY t3.invoice,t3.grp

你的其余问题有点含糊不清。如果两个范围长度相等,你想要两者还是最近的?如果任何消息=“是”,或者仅当最新消息=“是”时,输出MESSAGE应该为“是”吗?

这应该给你足够的面包屑