我有一个似乎是常见的业务请求,但我找不到明确的解决方案。我有一个每日报告(在众多报告中)根据失败的标准生成并保存到表中。每个报告都有一个与其绑定的类型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年看到过很多巧妙的技巧,但我无法访问它们。
非常感谢您的帮助!
答案 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应该为“是”吗?
这应该给你足够的面包屑