0

我是 SQL Server 的新手,有一个相当复杂的 SQL 任务,到目前为止我发现的解决方案都不适合我下面的问题。

我有一个数据库表,其中当前包含会员加入信息(下面的摘录),其中包含会员支付会员费的每一年/期间的一行;会员可以取消一年/期间的会员资格并在以后重新加入。我们需要将每个连续成员表示为一行,这样下面的提取 1 的内容就变成了提取 2:

提取物 1

Member_No    Start_Date                 End_Date
---------    ----------                 --------
10       2010-01-01 00:00:00.000    2011-01-01 00:00:00.000
10       2011-01-01 00:00:00.000    2012-01-01 00:00:00.000
10       2012-01-01 00:00:00.000    2013-01-01 00:00:00.000
10       2013-01-01 00:00:00.000    2014-01-01 00:00:00.000
20       2005-01-01 00:00:00.000    2006-01-01 00:00:00.000
20       2006-01-01 00:00:00.000    2007-01-01 00:00:00.000
20       2007-01-01 00:00:00.000    2008-01-01 00:00:00.000
30       2005-01-01 00:00:00.000    2006-01-01 00:00:00.000
30       2006-01-01 00:00:00.000    2007-01-01 00:00:00.000
30       2007-01-01 00:00:00.000    2008-01-01 00:00:00.000
30       2008-01-01 00:00:00.000    2009-01-01 00:00:00.000
30       2009-01-01 00:00:00.000    2010-01-01 00:00:00.000
30       2010-10-13 00:00:00.000    2011-01-01 00:00:00.000
30       2011-01-01 00:00:00.000    2012-01-01 00:00:00.000
30       2012-01-01 00:00:00.000    2013-01-01 00:00:00.000

我需要用下表替换上表的内容 - 有问题的表中有更多记录,我将非常感谢任何人可以提供的任何助手:

提取物 2

Member_No    Start_Date                 End_Date
---------    ----------                 --------
10       2010-01-01 00:00:00.000    2014-01-01 00:00:00.000
20       2005-01-01 00:00:00.000    2008-01-01 00:00:00.000
30       2005-01-01 00:00:00.000    2010-01-01 00:00:00.000
30       2010-10-13 00:00:00.000    2013-01-01 00:00:00.000
4

1 回答 1

0

这是一种更好的方法(原始方法仍在下方):

with ms as (
      select ms.*,
             (select 1 from Membership ms2 where ms2.Member_no = ms.Member_no and cast(ms2.Start_date as date) = cast(ms.End_date as date)
             ) as LinkedToNext
      from MemberShip ms
     )
select member_no, MIN(start_date) as start_date, MAX(end_date) as end_date
from (select ms.*,
             (select top 1 end_date
              from ms ms2 where ms2.Member_no = ms.Member_No and ms2.LinkedToNext is NULL and ms2.Start_Date >= ms.Start_Date
             order by end_date desc
             ) as grouping
      from ms
     ) ms1
group by Member_no, grouping

CTE 确定某事是否与下一个相关联。然后,分组是链接到链接链的下一个记录的第一个记录的结束日期,这始终是相同的。

回应您关于“不止一排”的评论。这意味着一个成员有两个从同一日期开始的成员资格。如果这是唯一的重叠形式,您可以将其修复为:

with ms as (
      select member_no, start_date, max(end_date) as end_date
             (select 1 from Membership ms2 where ms2.Member_no = ms.Member_no and cast(ms2.Start_date as date) = cast(ms.End_date as date)
             ) as LinkedToNext
      from MemberShip ms
      group by member_no, start_date
     )

比我原来的方法简单得多,我仍然保留在下面:

with ms as (
      select ms.*,
             (select 1 from Membership ms2 where ms2.Member_no = ms.Member_no and ms2.Start_date = ms.End_date
             ) as LinkedToNext,
             (select ms2.End_Date from Membership ms2 where ms2.Member_no = ms.Member_no and ms2.Start_date = ms.End_date
             ) as NextEndDate,
              (select 1 from Membership ms2 where ms2.Member_no = ms.Member_no and ms2.End_date = ms.Start_date
              ) as LinkedToPrev
      from MemberShip ms
     )
select member_no, MIN(start_date) as start_date,
       MAX(coalesce(NextEndDate, End_Date)) as  end_date
from (select ms.*,
             (ROW_NUMBER() over (partition by Member_no order by Start_Date) -
              ROW_NUMBER() over (partition by Member_no, LinkedToNext order by Start_date)
             ) as grouping
      from ms
     ) ms1
where not (LinkedToNext is null and LinkedToPrev = 1)
group by member_no, grouping

这使用相关的子查询来确定一个成员资格是否与下一个成员相关(基于开始日期与结束日期相同——如果您愿意,您实际上可以添加一个软糖因素)。

然后它使用了一个技巧。它按 start_date 为每个成员枚举行。它还根据每个成员是否链接到下一个成员,按开始日期枚举行。对于可以组合在一起的链,差异是恒定的。

最后一步是将其分组以获得最终结果。

一个复杂的问题是获得正确的结束日期。初始代码在计算中不包括链的末端。所以,我从下一条记录中借用了结束日期。然后它过滤掉这个结束记录。

于 2013-04-04T14:12:26.370 回答