2

对这个查询和一些提示/建议感到有点头疼,我们将不胜感激。我找不到与我的问题真正相关的任何东西 - 我在传递闭包上发现了一些东西,这不是我所需要的,因为我的数据可能会创建一个循环/循环,我认为这会导致递归调用无限循环.

假设我有两个基本表格,其下方显示数据。完全披露:Memberships表是一个 CTE,它已经做了相当多的逻辑来计算CServiceDate列的值。Transfers表是一个实际的表,除了 PK 和FromMembershipIDToMembershipID关系之外不包含很多 内容。

会员资格

 
+==========+===============+================+====== =========+
| 个人ID | 会员ID | 会员日期 | 服务日期 |
+==========+===============+================+====== =========+
| 1 | 15 | 2016 年 8 月 1 日 | 2017 年 8 月 27 日 |
+----------+--------------+----------------+------ --------+
| 1 | 16 | 2016 年 3 月 25 日 | 2000 年 9 月 1 日 |
+----------+--------------+----------------+------ --------+
| 1 | 17 | 2011 年 12 月 6 日 | 1995 年 5 月 15 日 |
+----------+--------------+----------------+------ --------+
| 1 | 18 | 2009 年 1 月 12 日 | 1998 年 2 月 28 日 |
+----------+--------------+----------------+------ --------+
| 1 | 19 | 2016 年 4 月 8 日 | 1994 年 7 月 10 日 |
+----------+--------------+----------------+------ --------+
| 1 | 20 | 2010 年 6 月 11 日 | 1997 年 11 月 12 日 |
+----------+--------------+----------------+------ --------+

转移

+=====+=====+===================+================+
| 时间 | PID | FromMembershipID | ToMembershipID |
+=====+=====+===================+================+
| 1 | 1 | 16 | 15 |
+-----+-----+------------------+----------------+
| 2 | 1 | 18 | 17 |
+-----+-----+------------------+----------------+
| 3 | 1 | 19 | 17 |
+-----+-----+------------------+----------------+
| 4 | 1 | 20 | 18 |
+-----+-----+------------------+----------------+
| 5 | 1 | 20 | 19 |
+-----+-----+------------------+----------------+

问题 我需要从查询中获取 Memberships CTE 中的每一行(即每个 MembershipID),我想返回所有相关 MembershipID 的 MIN CServiceDate。我将此 MIN 值称为 ECSD(预期信用服务日期)。ECSD的计算只有两个条件:

  • 如果通过查看 FromMembershipID 和 ToMembershipID 列,通过Transfers表以某种方式将成员资格记录与当前 MembershipID 关联,则该成员资格记录被视为与当前 MembershipID“相关”。例如,对于 MembershipID 20,如果我们查看Transfers表,我们可以看到 MembershipIDs 20、19、18 和 17 都是通过传递性相关的(此外:通过Transfers表,我们可以看到 MembershipIDs 15 和 16 与彼此,但不是 [20,19,18,17] )
  • 在上面直接派生的可传递相关成员列表中,在计算 ECSD 时可在传递关系列表中考虑的唯一成员是 MembershipDate 早于当前 MembershipID 的成员。例如,基于给定 MembershipID 的 MembershipDates 和Transfers表,如果查看 MembershipID 17,则在计算 MembershiID 17 的 ECSD 时不能考虑 MembershipID 19,因为 MembershipID 19 的 MembershipDate(2016 年 4 月 8 日)不早于MembershipID 17's (Dec-06-2011)

ECSD 列的预期输出

+==========+===============+================+====== ========+==============+
| 个人ID | 会员ID | 会员日期 | 服务日期 | 教育发展署 |
+==========+===============+================+====== ========+==============+
| 1 | 15 | 2016 年 8 月 1 日 | 2017 年 8 月 27 日 | 2000 年 9 月 1 日 |
+----------+--------------+----------------+------ --------+-------------+
| 1 | 16 | 2016 年 3 月 25 日 | 2000 年 9 月 1 日 | 2000 年 9 月 1 日 |
+----------+--------------+----------------+------ --------+-------------+
| 1 | 17 | 2011 年 12 月 6 日 | 1995 年 5 月 15 日 | 1995 年 5 月 15 日 |
+----------+--------------+----------------+------ --------+-------------+
| 1 | 18 | 2009 年 1 月 12 日 | 1998 年 2 月 28 日 | 1998 年 2 月 28 日 |
+----------+--------------+----------------+------ --------+-------------+
| 1 | 19 | 2016 年 4 月 8 日 | 1994 年 7 月 10 日 | 1994 年 7 月 10 日 |
+----------+--------------+----------------+------ --------+-------------+
| 1 | 20 | 2010 年 6 月 11 日 | 1997 年 11 月 12 日 | 1997 年 11 月 12 日 |
+----------+--------------+----------------+------ --------+-------------+

请注意:

  • MembershipID 可以在 FromMembershipID 和 ToMembershipID 列中显示多次。这些列值不必是唯一的。
  • 上面提供的表格是简单的关系。成员资格/转移可以低至 1 层深度(即 1 次转移)到 N 层深度,其中转移(如果仅查看 From/ToMembershipID)可以创建循环循环。下面是一个传输关系更深的例子。
  • 可能需要注意的是,如果 TOMembershipID 列中不存在 MembershipID,则该 MembershipID 是最早的(可能有多个)。类似地,如果 FromMembershipID 列中不存在 MembershipID,则它是结束的和最新的成员资格。
    • 对于给定的人,可能存在将某些成员资格联系在一起的块或转移集,但不是全部。

示例 2

会员资格

+==========+===============+================+====== =========+
| 人物 | 会员ID | 会员日期 | 服务日期 |
+==========+===============+================+====== =========+
| 499510 | 548426 | 2014-09-29 | 2014-09-29 |
+----------+--------------+----------------+------ --------+
| 499510 | 548428 | 2014-01-29 | 2014-01-29 |
+----------+--------------+----------------+------ --------+
| 499510 | 548425 | 2012-05-28 | 2012-05-28 |
+----------+--------------+----------------+------ --------+
| 499510 | 548429 | 2011-11-23 | 2011-11-23 |
+----------+--------------+----------------+------ --------+
| 499510 | 548427 | 2008-07-03 | 2008-07-03 |
+----------+--------------+----------------+------ --------+
| 499510 | 548431 | 2001-05-01 | 1976-01-01 |
+----------+--------------+----------------+------ --------+
| 499510 | 548430 | 1998-10-08 | 1998-10-08 |
+----------+--------------+----------------+------ --------+

转移

+=======+=========+==================+============= ===+
| 时间 | 进程号 | FromMembershipID | ToMembershipID |
+=======+=========+==================+============= ===+
| 10664 | 499510 | 548430 | 548431 |
+-------+--------+------------------+------------- ---+
| 10665 | 499510 | 548431 | 548427 |
+-------+--------+------------------+------------- ---+
| 10666 | 499510 | 548427 | 548429 |
+-------+--------+------------------+------------- ---+
| 10667 | 499510 | 548429 | 548425 |
+-------+--------+------------------+------------- ---+
| 10668 | 499510 | 548425 | 548428 |
+-------+--------+------------------+------------- ---+
| 10669 | 499510 | 548428 | 548426 |
+-------+--------+------------------+------------- ---+
| 13085 | 499510 | 548430 | 548427 |
+-------+--------+------------------+------------- ---+
| 13086 | 499510 | 548427 | 548425 |
+-------+--------+------------------+------------- ---+
| 13087 | 499510 | 548425 | 548426 |
+-------+--------+------------------+------------- ---+
| 13088 | 499510 | 548431 | 548429 |
+-------+--------+------------------+------------- ---+
| 13089 | 499510 | 548429 | 548428 |
+-------+--------+------------------+------------- ---+

预期结果

+==========+===============+================+====== ========+=============+
| 人物 | 会员ID | 会员日期 | 服务日期 | 教育发展署 |
+==========+===============+================+====== ========+=============+
| 499510 | 548426 | 2014-09-29 | 2014-09-29 | 1976-01-01 |
+----------+--------------+----------------+------ --------+------------+
| 499510 | 548428 | 2014-01-29 | 2014-01-29 | 1976-01-01 |
+----------+--------------+----------------+------ --------+------------+
| 499510 | 548425 | 2012-05-28 | 2012-05-28 | 1976-01-01 |
+----------+--------------+----------------+------ --------+------------+
| 499510 | 548429 | 2011-11-23 | 2011-11-23 | 1976-01-01 |
+----------+--------------+----------------+------ --------+------------+
| 499510 | 548427 | 2008-07-03 | 2008-07-03 | 1976-01-01 |
+----------+--------------+----------------+------ --------+------------+
| 499510 | 548431 | 2001-05-01 | 1976-01-01 | 1976-01-01 |
+----------+--------------+----------------+------ --------+------------+
| 499510 | 548430 | 1998-10-08 | 1998-10-08 | 1998-10-08 |
+----------+--------------+----------------+------ --------+------------+

谢谢!

4

1 回答 1

3

这是一种使用 CTE 编译传递关系列表的方法。一个 CTE 递归地定义从 FromMembershipID 到 ToMembershipID 的关系。第二个 CTE 在相反的方向上做同样的事情 - 这样,您可以将结果组合到第三个 CTE 中,列出成员资格之间的每个传递关系。

例如,在第一个结果集中,20 => 19 和 19 => 17,反过来,17 => 19 和 19 => 20,所以你得到:

20   19
20   17
19   17
17   19
17   20
19   20

然后,您可以使用该列表传递关系按成员资格获取最小 CServiceDate。

这为两组样本数据提供了正确的输出。如果您有更多数据,您可能会遇到 100 级递归限制,但您可以对其进行配置。或找到更好的解决方案:) 但从技术上讲,这是可行的:

;with cte_trans_relationships (frommembershipid, tomembershipid)
as
(
    select frommembershipid, tomembershipid
    from @transfer
    union all
    select c.frommembershipid, t.tomembershipid
    from cte_trans_relationships c
    inner join @transfer t on c.tomembershipid = t.frommembershipid
),
cte_trans_relationships2 (tomembershipid, frommembershipid)
as
(
    select tomembershipid, frommembershipid
    from @transfer
    union all
    select c.tomembershipid, t.frommembershipid
    from cte_trans_relationships c
    inner join @transfer t on c.frommembershipid = t.tomembershipid
),
cte_trans_all (m1, m2)
as
(
    select distinct frommembershipid m1, tomembershipid m2
    from cte_trans_relationships c
    union 
    select distinct tomembershipid, frommembershipid
    from cte_trans_relationships2 c2    
)
select m.personid, m.membershipid, m.membershipdate, m.cservicedate, 
    case when sq.cservicedate < cservicedate1 and sq.cservicedate < cservicedate2 then sq.cservicedate
    when cservicedate1 < sq.cservicedate and cservicedate1 < cservicedate2 then cservicedate1
    else cservicedate2 end as ECSD
from @memberships m
inner join 
(
    select m.personid, m.membershipid, isnull(m.cservicedate, dateadd(year, 100, getdate())) as cservicedate, 
    isnull(min(m1.cservicedate), dateadd(year, 100, getdate())) as cservicedate1,
    isnull(min(m2.cservicedate), dateadd(year, 100, getdate())) as cservicedate2
    from @memberships m
    left join cte_trans_all sq_trans1 on m.membershipid = sq_trans1.m1
    left join @memberships m1 on sq_trans1.m2 = m1.membershipid and m1.membershipdate < m.membershipdate
    left join cte_trans_all sq_trans2 on m.membershipid = sq_trans2.m1
    left join @memberships m2 on sq_trans2.m2 = m2.membershipid and m2.membershipdate < m.membershipdate
    group by m.personid, m.membershipid, m.cservicedate
)sq on m.personid = sq.personid and m.membershipid = sq.membershipid

以下是用于测试的示例 DDL/DML 语句:

declare @memberships table (personid int, membershipid int, membershipdate datetime, cservicedate datetime)
insert into @memberships values (1, 15, '8/1/2016', '8/27/2017')
insert into @memberships values (1, 16, '3/25/2016', '9/1/2000')
insert into @memberships values (1, 17, '12/6/2011', '5/15/1995')
insert into @memberships values (1, 18, '1/12/2009', '2/28/1998')
insert into @memberships values (1, 19, '4/8/2016', '7/10/1994')
insert into @memberships values (1, 20, '6/11/2010', '11/12/1997')
--insert into @memberships values (499510, 548426, '9/29/2014', '9/29/2014')
--insert into @memberships values (499510, 548428, '1/29/2014', '1/29/2014')
--insert into @memberships values (499510, 548425, '5/28/2012', '5/28/2012')
--insert into @memberships values (499510, 548429, '11/23/2011', '11/23/2011')
--insert into @memberships values (499510, 548427, '7/3/2008', '7/3/2008')
--insert into @memberships values (499510, 548431, '5/1/2001', '1/1/1976')
--insert into @memberships values (499510, 548430, '10/8/1998', '10/8/1998')

declare @transfer table (tid int, pid int, frommembershipid int, tomembershipid int)
insert into @transfer values (1, 1, 16, 15)
insert into @transfer values (2, 1, 18, 17)
insert into @transfer values (3, 1, 19, 17)
insert into @transfer values (4, 1, 20, 18)
insert into @transfer values (5, 1, 20, 19)
--insert into @transfer values (10664, 499510, 548430, 548431)
--insert into @transfer values (10665, 499510, 548431, 548427)
--insert into @transfer values (10666, 499510, 548427, 548429)
--insert into @transfer values (10667, 499510, 548429, 548425)
--insert into @transfer values (10668, 499510, 548425, 548428)
--insert into @transfer values (10669, 499510, 548428, 548426)
--insert into @transfer values (13085, 499510, 548430, 548427)
--insert into @transfer values (13086, 499510, 548427, 548425)
--insert into @transfer values (13087, 499510, 548425, 548426)
--insert into @transfer values (13088, 499510, 548431, 548429)
--insert into @transfer values (13089, 499510, 548429, 548428)

以下是 2 个结果集:

personid  membershipid  membershipdate    cservicedate  ECSD
1         15            2016-08-01        2017-08-27    2000-09-01
1         16            2016-03-25        2000-09-01    2000-09-01
1         17            2011-12-06        1995-05-15    1995-05-15
1         18            2009-01-12        1998-02-28    1998-02-28
1         19            2016-04-08        1994-07-10    1994-07-10
1         20            2010-06-11        1997-11-12    1997-11-12

personid    membershipid    membershipdate  cservicedate    ECSD
499510      548425          2012-05-28      2012-05-28      1976-01-01
499510      548426          2014-09-29      2014-09-29      1976-01-01
499510      548427          2008-07-03      2008-07-03      1976-01-01
499510      548428          2014-01-29      2014-01-29      1976-01-01
499510      548429          2011-11-23      2011-11-23      1976-01-01
499510      548430          1998-10-08      1998-10-08      1998-10-08
499510      548431          2001-05-01      1976-01-01      1976-01-01
于 2017-08-10T15:49:10.253 回答