Sql server 根据日期范围选择最大记录数。(日期在相互之间的6个月内)
我有一张日期表 我需要能够选择相互之间在6个月内存在的最大数量的记录 然后是下一个最大数量的记录,依此类推,直到选中所有记录 这是数据Sql server 根据日期范围选择最大记录数。(日期在相互之间的6个月内),sql-server,tsql,sql-server-2005,Sql Server,Tsql,Sql Server 2005,我有一张日期表 我需要能够选择相互之间在6个月内存在的最大数量的记录 然后是下一个最大数量的记录,依此类推,直到选中所有记录 这是数据 1 19-Oct-2007 2 03-Dec-2007 3 16-Oct-2009 4 26-Oct-2009 5 30-Oct-2009 6 01-Nov-2009 7 16-Nov-2009 8 30-Nov-2009 9 11-Dec-2009 10 25-Dec-2009 11 01-Jan-2010 12 21-Jan-2010
1 19-Oct-2007
2 03-Dec-2007
3 16-Oct-2009
4 26-Oct-2009
5 30-Oct-2009
6 01-Nov-2009
7 16-Nov-2009
8 30-Nov-2009
9 11-Dec-2009
10 25-Dec-2009
11 01-Jan-2010
12 21-Jan-2010
13 27-Jan-2010
14 28-Jan-2010
15 28-Jan-2010
16 12-Feb-2010
17 12-Feb-2010
18 27-Feb-2010
19 09-Mar-2010
20 22-Mar-2010
21 26-Mar-2010
22 01-Apr-2010
23 22-Oct-2010
24 15-Oct-2011
25 18-Oct-2011
26 26-Oct-2011
27 16-Nov-2011
28 18-Nov-2011
29 19-Nov-2011
30 26-Nov-2011
31 29-Nov-2011
32 29-Nov-2011
33 30-Nov-2011
34 06-Dec-2011
35 16-Dec-2011
36 17-Dec-2011
37 20-Dec-2011
38 28-Dec-2011
39 01-Jan-2012
40 01-Jan-2012
41 09-Jan-2012
42 13-Jan-2012
43 27-Jan-2012
44 01-Feb-2012
45 23-Feb-2012
46 29-Feb-2012
47 01-Mar-2012
48 01-Mar-2012
49 01-Mar-2012
50 02-Mar-2012
51 04-Mar-2012
52 04-Mar-2012
53 05-Mar-2012
54 05-Mar-2012
55 17-Mar-2012
56 23-Mar-2012
57 24-Mar-2012
58 01-Apr-2012
59 03-Apr-2012
60 04-Apr-2012
一个可能的解决办法是选择
- 记录24-60(彼此之间在172天内)
- 记录23(不在前一个/下一个日期的6个月内)
- 记录3-22(彼此在167天内)
- 记录1-2(彼此在45天内)
选择d1.date,count(*)
起始日期为d1,带有(nolock)
将日期作为d2与(nolock)连接
日期差(mm,d2.日期,d1.日期)<6
按d1.1日期分组
按计数排序(*)说明
我考虑过
create table #list (id int, dt datetime )
-- insert you data into #list
select s1.id as ID_1, s1.dt as Date_2 , s2.id as ID_2, s2.dt as Date_2
,abs( datediff(day, s2.dt, s1.dt) ) diff_in_days
from #list s1 , #list s2
order by case when abs(datediff(day, s2.dt, s1.dt) ) > 180 then 1
else abs(datediff(day, s2.dt, s1.dt)) end desc
我使用了我自己的测试数据,这是非常复杂的东西。使用光标可能更容易处理。但我不太喜欢用光标。我已经尽了最大努力:
declare @t table(record int, date datetime)
insert @t values(1,'19-Oct-2007'),
(2,'03-Dec-2007'),
(3,'2-may-2009'),
(4,'16-Oct-2009'),
(5,'26-Oct-2009'),
(6,'30-Oct-2009'),
(7,'01-Nov-2009'),
(8,'16-Nov-2009'),
(9,'30-Nov-2009'),
(10,'11-Dec-2009'),
(11,'11-Dec-2010'),
(12,'11-Dec-2010'),
(13,'11-Dec-2010')
;with a as
(
select datediff(day, t1.date, t2.date) daysapart,
row_number() over (order by count desc) rn,
b.count,
t1.record fromrecord,
t2.record torecord
from @t t1
join @t t2
on t1.date <= t2.date
and dateadd(month, 6, t1.date) > t2.date
and t1.record <= t2.record
cross apply (select count(*) count from @t where record between t1.record and t2.record) b
)
, b as
(
select * from a where not exists
(select 1 from a b where (a.fromrecord between b.fromrecord and b.torecord
or a.torecord between b.fromrecord and b.torecord)
and a.rn > b.rn and not exists(select 1 from a c where
(b.fromrecord between c.fromrecord and c.torecord
or b.torecord between c.fromrecord and c.torecord)
and b.rn > c.rn))
)
select count, fromrecord, torecord, daysapart from b
下面是解决这个问题的迭代方法,目前我没有比这更好的建议了。不过,它应该会起作用:
WITH ranked AS (
SELECT *, rnk = ROW_NUMBER() OVER (ORDER BY Date DESC)
FROM data
),
marked AS (
SELECT
rnk,
Date,
GroupDate = date
FROM ranked
WHERE rnk = 1
UNION ALL
SELECT
r.rnk,
r.Date,
GroupDate = CASE
WHEN m.GroupDate > DATEADD(MONTH, 6, r.Date) THEN r.Date
ELSE m.GroupDate
END
FROM ranked r
INNER JOIN marked m ON r.rnk = m.rnk + 1
)
SELECT
MinDate = MIN(Date),
MaxDate = MAX(Date),
[RowCount] = COUNT(*),
RangeLength = DATEDIFF(DAY, MIN(Date), MAX(Date))
FROM marked
GROUP BY
GroupDate
ORDER BY
GroupDate
就是
MinDate MaxDate RowCount RangeLength
---------- ---------- ----------- -----------
2007-10-19 2007-12-03 2 45
2009-10-16 2010-04-01 20 167
2010-10-22 2010-10-22 1 0
2011-10-15 2012-04-04 37 172
整个脚本,包括设置,都可以找到并使用。我尝试了你的脚本,但没有给出正确或非常正确的结果。这是我先前的修正comment@t-clausen.dk你能告诉我1>在问题的给定数据集中,我的第一行输出应该是什么吗?对我来说,理解是-在数据集中,找出以6M为单位的日期之间的差异,并按降序排列。所以你假设作者想要3600行作为结果集?不知道... 你能指定他想要什么吗?@t-clausen.dk我在SQL 2008 R2上测试了它。哪一部分对你不起作用?在你纠正语法后,结果才是错误的。试试@andryMI的脚本对不起,我写得太早了。这是不对的。@t-clausen.dk:我不确定我是否理解这个解决方案的问题所在,但我很想尝试解决它,特别是因为你已经对我的答案投了更高的票。用这些日期试试你的问题,应该很清楚:(1,'2012-01-01'),(2,'2012-01-01'),(3,'2012-03-01'),(4,'2012-03-01'),(5,'2012-08-01'))@克劳森:谢谢。我看不出我得到的结果有什么不对,但我想也许我们对这个问题的理解不同。我想我现在明白你是怎么理解的了(这可能比我的理解更正确)。你认为查询必须找到彼此相隔6个月的日期的最大子集,不是吗?最初文章中的一些线索,我一开始肯定错过了,确实支持这一观点。我认为可以使用递归CTE来找到一个(最大的)这样的子集。但是,到目前为止,找到所有这些似乎是一项复杂得多的任务。我同意这是一项复杂的任务。这正是我在我的查询中尝试的,它似乎有效。这有点令人兴奋,但它有效!我对您的解决方案的一个(相当小的)挑剔是这样的条件:
datediff(day,t1.date,t2.date)介于0和180之间。我真的想把它改成:t2.date@AndriyM谢谢你的评论和好话。在日期问题上有很好的发现。我刚刚醒来并登录以更改它,因为它困扰着我。要不然我早上从来不会这么早起床。这将无法很好地扩展大型数据集
WITH ranked AS (
SELECT *, rnk = ROW_NUMBER() OVER (ORDER BY Date DESC)
FROM data
),
marked AS (
SELECT
rnk,
Date,
GroupDate = date
FROM ranked
WHERE rnk = 1
UNION ALL
SELECT
r.rnk,
r.Date,
GroupDate = CASE
WHEN m.GroupDate > DATEADD(MONTH, 6, r.Date) THEN r.Date
ELSE m.GroupDate
END
FROM ranked r
INNER JOIN marked m ON r.rnk = m.rnk + 1
)
SELECT
MinDate = MIN(Date),
MaxDate = MAX(Date),
[RowCount] = COUNT(*),
RangeLength = DATEDIFF(DAY, MIN(Date), MAX(Date))
FROM marked
GROUP BY
GroupDate
ORDER BY
GroupDate
MinDate MaxDate RowCount RangeLength
---------- ---------- ----------- -----------
2007-10-19 2007-12-03 2 45
2009-10-16 2010-04-01 20 167
2010-10-22 2010-10-22 1 0
2011-10-15 2012-04-04 37 172