当另一行出现时,检索具有最新日期的数据行<&燃气轮机';X';在T-SQL中

当另一行出现时,检索具有最新日期的数据行<&燃气轮机';X';在T-SQL中,sql,sql-server,tsql,date,greatest-n-per-group,Sql,Sql Server,Tsql,Date,Greatest N Per Group,我有一个客户数据库,他们的会员资格有生效日期和结束日期,这两个列都是分开的。但是,数据有点脏,客户可以有多行数据,其中只有一行是他们最近的成员记录。如果成员的结束日期为空,则该成员被视为“活动” 数据看起来有点像这样: Name ID Membership_Effective_Date Membership_End_Date -----------------------------------------------------------------

我有一个客户数据库,他们的会员资格有生效日期和结束日期,这两个列都是分开的。但是,数据有点脏,客户可以有多行数据,其中只有一行是他们最近的成员记录。如果成员的结束日期为空,则该成员被视为“活动”

数据看起来有点像这样:

Name         ID          Membership_Effective_Date     Membership_End_Date
---------------------------------------------------------------------------
Bob           1                 1/1/2020                           NULL
Bob           1                 1/1/2017                           1/2/2017
Bob           1                 1/1/2017                           9/1/2018
Kim           2                 1/1/2019                           1/1/2020
Kim           2                 1/1/2019                           12/31/2019
Susan         3                 1/1/2018                           12/31/2018
Susan         3                 1/1/2019                           1/1/2019
Larry         4                 1/1/2020                           1/1/2020
我需要检索非活动和活动客户列表的最近成员资格结束日期

我想要的结果应该是这样的:

Name         ID          Membership_Effective_Date     Membership_End_Date
---------------------------------------------------------------------------
Bob           1                 1/1/2020                           NULL
Bob           1                 1/1/2017                           1/2/2017
Bob           1                 1/1/2017                           9/1/2018
Kim           2                 1/1/2019                           1/1/2020
Kim           2                 1/1/2019                           12/31/2019
Susan         3                 1/1/2018                           12/31/2018
Susan         3                 1/1/2019                           1/1/2019
Larry         4                 1/1/2020                           1/1/2020

姓名ID成员资格\生效日期成员资格\结束日期
Bob 1 1/1/2020空
Kim 2 2019年1月1日2020年1月1日
Susan 3 2018年1月1日2018年12月31日
拉里4 1/1/2020 1/1/2020

对于既有一行具有Membership_End_Date值,又有一行具有NULL值(Bob)的Membership_End_Date行的客户,以及有多行仅具有日期值(Kim)的客户,我能够做到这一点而没有问题

我面临的挑战是如何处理像Susan和Larry这样的数据。它们都有包含日期值的行,其中成员资格\生效\日期=成员资格\结束\日期。在拉里的案例中,这是他拥有的唯一一行数据。在Susan的例子中,Membership\u Effective\u Date=Membership\u End\u Date行中的日期大于另一行,因此我当前的查询将自动获取它

问题是,我基本上需要编写一个查询,如果客户有多行数据,其中一行的成员资格\有效\日期=成员资格\结束\日期,则选择第二行最近的数据。但是,如果客户只有一行数据,且该行仅包含成员资格\生效\日期=成员资格\结束\日期的值,则选择该行

如果不将Larry完全从数据拉取中移除,我无法想出如何做到这一点,我需要将他和类似的客户包括在内


感谢您的帮助

您可以使用
行号()和条件排序来完成此操作:

select name, id, membership_effective_date, membership_end_date
from (
    select 
        t.*,
        row_number() over(
            partition by id 
            order by
                case when membership_end_date is null then 0 else 1 end,
                case when membership_end_date <> membership_effective_date then 0 else 1 end,
                membership_end_date desc
        ) rn
    from mytable t
) t
where rn = 1
不知道是什么让你觉得你的代码更好

首先,恕我直言,不要冒犯任何人

order by
    case when membership_end_date is null then 0 else 1 end,
    case when membership_end_date <> membership_effective_date then 0 else 1 end,
      membership_end_date desc
是的,当我使用CTE时,你是对的,它至少要扫描两次

现在我使用的是
#temp
表,但想法和前面一样


或多或少,我只坚持这个想法。

请向我们展示您期望的结果,以及您现有的查询。您能更好地解释一下您正在做什么吗?您提到了活动和非活动成员身份,但没有列指定这一点。然后,让这两个日期相同似乎意味着什么,但不清楚是什么。您可以使用分区设置
行号()
,以获得所需的结果。“如果成员的结束日期为空,则认为该成员是“活动的”。因此,非活动成员是结束日期为某个日期的成员。我想知道是什么让你认为你的代码更好,而在大多数情况下可能更糟。我强烈建议检查执行计划和IO的统计信息。假设我们没有索引(因为op没有提供任何DDL),那么您的代码可能会扫描表三次,并且需要使用联接或嵌套循环。你能详细解释一下为什么你避免使用Row_NumberSry,但在论坛上,我不知道我在和谁说话,所以我只能根据我们这里的情况做出假设,这意味着我可能会犯错误。。。话虽如此,我必须问问您是否了解执行计划、SQL Server统计数据和监控性能,因为您的查询非常糟糕(轻描淡写)。首先,你完全改变了我回答的问题,使我的评论变得无关紧要,这是我的主要原因!如果你改变历史,我们就不能进行讨论。其次,您的新查询非常糟糕。不幸的是,stackoverflow系统不适合进行讨论。我们甚至不能将图片上传到回复,也不能有任何格式文本或格式代码@KumarHarsh,我只能建议(1)检查有关如何监控SQL Server性能的更多信息。(2) 不要仅仅因为你不喜欢某个东西就避免使用它,更重要的是不要试图不惜一切代价强迫你的观点,而你自己却不去实际查看其他选项。祝你好运,在论坛上帮助他人做得很好
    create table customers1(Name varchar(40),  ID int
    , Membership_Effective_Date datetime, Membership_End_Date datetime)
    insert into customers1 values
    ('Bob',           1    ,'2020-01-01' ,       NULL)
    ,('Bob',           1    ,'2017-01-01' ,     '1/2/2017')
    ,('Bob',           1    ,'2017-01-01' ,   '9/1/2018')
    ,('Kim',           2  ,'2019-01-01' ,   '1/1/2020')
    ,('Kim',           2   ,'2019-01-01' ,  '12/31/2019')
    ,('Susan',         3  ,'2018-01-01' ,  '12/31/2018')
    ,('Susan',         3  ,'2019-01-01' ,  '1/1/2019')
    ,('Larry',         4   ,'2020-01-01' ,   '1/1/2020')

SELECT ID
    ,NAME
    ,Membership_Effective_Date
    ,Membership_End_Date
INTO #temp
FROM customers1
WHERE Membership_End_Date IS NULL
OPTION (MAXDOP 1)

SELECT ID
    ,NAME
    ,Membership_Effective_Date
    ,Membership_End_Date
FROM #temp

UNION ALL

SELECT t.ID
    ,t.NAME
    ,min(t.Membership_Effective_Date) AS Membership_Effective_Date
    ,max(t.Membership_End_Date) AS Membership_End_Date
FROM customers1 t
WHERE Membership_End_Date IS NOT NULL
    AND NOT EXISTS (
        SELECT 1
        FROM #temp ac
        WHERE ac.ID = t.ID
        )
GROUP BY t.ID
    ,t.NAME
OPTION (MAXDOP 1)


drop table #temp
drop table customers1