当另一行出现时,检索具有最新日期的数据行<&燃气轮机';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