问题描述
我有一张可选择日期的桌子。我希望能够应用WHERE语句返回一组,然后从一个列返回最早的日期,而从另一列返回最晚的日期。这是一个示例表:
ID StartDate EndDate Person Subject
1 01/03/2010 03/03/2010 Paul Math
2 12/05/2010 22/05/2010 Steve Science
3 04/03/2010 08/03/2010 Paul English
所以我想返回Person ='Paul'的所有记录。但是返回类似(最早的)StartDate = 01/03/2010(来自记录ID 1)和(最新的)EndDate = 08/03/2010(来自记录ID 3)和Subject =来自最新的EndDate(来自记录3)的东西。我需要为保罗提供上述数据和Id的两行。需要所有与person ='Paul'
的行预期结果:
ID StartDate EndDate Person Subject
1 2010-03-01 2010-03-08 Paul English
3 2010-03-01 2010-03-08 Paul English
您是否在以下SQL查询中看到有关性能(数百万条记录)的任何问题:
Select PT3.ID,PT4.EarliestStartDate AS StartDate,PT4.EndDate,PT4.Person,PT4.Subject from Data AS PT3
Join( SELECT Top 1 with ties * FROM Data AS PT
Join( SELECT PT1.Person as Person1,MIN(PT1.StartDate ) as EarliestStartDate FROM Data AS PT1 where Person ='Paul' group by PT1.Person) AS PT2 ON PT.Person =PT2.Person1WHERE Person ='Paul'
Order By Row_Number() over (Partition By PT.Person Order By PT.EndDate desc)) AS PT4 ON PT3.Person = PT4.Person
解决方法
这可能有效:
- 首先执行
group by
,以获取每个人所需的日期。 - 将分组移动到公用表表达式(
cte
)。 - 重新加入完整的数据集以获取所有行。
- 对于每个结果记录,请选择带有
cross apply
的相应主题。 - 可选:过滤所需人员(
where
子句)。
样本数据
create table Data
(
ID int,StartDate date,EndDate date,Person nvarchar(10),Subject nvarchar(10)
);
insert into Data (ID,StartDate,EndDate,Person,Subject) values
(1,'2010-03-01','2010-03-03','Paul','Math'),(2,'2010-05-12','2010-05-22','Steve','Science'),(3,'2010-03-04','2010-03-08','English');
解决方案
with cte as
(
select min(d.StartDate) as StartDate,max(d.EndDate) as EndDate,d.Person
from Data d
group by d.Person
)
select d.Id,c.StartDate,c.EndDate,c.Person,x.Subject
from cte c
join data d
on d.Person = c.Person
cross apply ( select top 1 d2.Subject
from Data d2
where d2.Person = c.Person
and d2.EndDate = c.EndDate ) x
where d.Person = 'Paul'
order by d.Person;
Fiddle来查看实际效果。
,这应该为您提供正确的值。
DECLARE @values TABLE (
Id INT,StartDate DATETIME2,EndDate DATETIME2,Person NVARCHAR(MAX),Subject NVARCHAR(MAX))
INSERT INTO @values VALUES
(1,'2101-03-04','English')
;WITH sort AS (
SELECT
Person,MIN(StartDate) OVER(PARTITION BY Person) StartDate,MAX(EndDate) OVER(PARTITION BY Person) EndDate,Subject,ROW_NUMBER() OVER(PARTITION BY Person ORDER BY EndDate DESC) rownum
FROM @values v)
SELECT
Person,Subject
FROM sort
WHERE rownum = 1
它将为您提供以下结果:
Person MinStartDate MaxEndDate Subject
Paul 2010-03-01 2010-03-08 English
Steve 2010-05-12 2010-05-22 Science
,
如果您只关心选择Pauls数据,这应该就足够了:
SELECT
Person,MIN(startDate) AS Earliest,MAX(EndDate) AS Latest,(
SELECT TOP 1 Subject
FROM Data
WHERE Person = 'Paul'
ORDER BY EndDate DESC
) AS Subject
FROM Data WHERE Person = 'Paul'
如果您想选择所有人,这应该起作用:
SELECT
d1.Person,MIN(d1.startDate) AS Earliest,MAX(d1.EndDate) AS Latest,(
SELECT TOP 1 d2.Subject
FROM Data d2
WHERE d2.Person = d1.Person
ORDER BY EndDate DESC
) AS Subject
FROM Data d1
GROUP BY d1.Person
编辑:您似乎希望对表中的每一行都有结果,而不是每个人只有一个,但是总要显示最早和最新的日期。这是你的追求吗?
SELECT
d1.Id,d1.Person,(
SELECT MIN(d1.StartDate) AS Earliest
FROM Data d2
WHERE d2.Person = d1.Person
) AS Earliest,(
SELECT MAX(d1.EndDate) AS Latest
FROM Data d2
WHERE d2.Person = d1.Person
) AS Latest,(
SELECT TOP 1 d2.Subject
FROM Data d2
WHERE d2.Person = d1.Person
ORDER BY EndDate DESC
) AS Subject
FROM Data d1