SQL Server 2008 R2:使用多个 CTE 获取日期明智的记录
Posted
技术标签:
【中文标题】SQL Server 2008 R2:使用多个 CTE 获取日期明智的记录【英文标题】:SQL Server 2008 R2: Get date wise records using multiple CTE 【发布时间】:2018-05-25 11:07:25 【问题描述】:我有下表:
表:TblLocation
CREATE TABLE TblLocation
(
ColDate DATE,
ColTime time,
Colvalue VARCHAR(50)
);
INSERT INTO TblLocation VALUES('2018-01-01','01:10:11','Location1');
INSERT INTO TblLocation VALUES('2018-01-01','02:10:11','Location2');
INSERT INTO TblLocation VALUES('2018-01-01','03:10:11','Location3');
INSERT INTO TblLocation VALUES('2018-01-01','11:10:11','Location4');
INSERT INTO TblLocation VALUES('2018-01-02','01:10:11','Location1');
INSERT INTO TblLocation VALUES('2018-01-02','02:10:11','Location2');
INSERT INTO TblLocation VALUES('2018-01-02','03:10:11','Location2');
INSERT INTO TblLocation VALUES('2018-01-02','01:10:11','Location3');
INSERT INTO TblLocation VALUES('2018-01-02','03:15:11','Location4');
INSERT INTO TblLocation VALUES('2018-01-03','02:10:11','Location1');
INSERT INTO TblLocation VALUES('2018-01-03','02:50:11','Location1');
INSERT INTO TblLocation VALUES('2018-01-03','03:10:11','Location1');
注意:我想找到每个日期的第一个、中间和最后一个位置。
预期输出:
ColDate FirstLocation MidLocation LastLocation
-------------------------------------------------------------
2018-01-01 Location1 Location3 Location4
2018-01-02 Location1 Location2 Location4
2018-01-03 Location1 NULL Location1
输出说明:
FirstLocation - 这应该基于 ORDER by date 和 time,并且将是该日期的 FIRST time。
MidLocation - 这不应该等于 FirstLocation 和 LastLocation 但它是 存在于数量更多或任何平局的位置之间。 如果两者之间没有任何内容,则为 NULL,如第 3 行所示。
LastLocation - 这应该基于 ORDER 按日期和时间,并且将是该日期的 LAST 时间。
我的尝试:
WITH CTEMain AS
(
SELECT ColDate,ColTime, ColValue, ROW_NUMBER() OVER(PARTITION BY ColDate ORDER BY ColDate,ColTime ASC) Rn
FROM dbo.TblLocation
),
CTEMinMax AS
(
SELECT MIN(Rn) AS MinRn,MAX(Rn) AS MaxRn
FROM CTEMain
),
CX AS
(
SELECT c1.ColDate,c1.Colvalue AS FirstLocation,
c2.Colvalue AS LastLocation
FROM CTEMain c1
INNER JOIN CTEMinMax cmin ON c1.Rn = cmin.MinRn
INNER JOIN CTEMain c2 ON 1 = 1
INNER JOIN CTEMinMax cmax ON c2.Rn = cmax.MaxRn
),
CXX AS
(
SELECT TOP 1 ROW_NUMBER() OVER(PARTITION BY Colvalue ORDER BY Rn DESC) Rnk,ColValue,Rn
FROM CTEMain c1
INNER JOIN CX x ON c1.colvalue <> x.FirstLocation AND c1.colvalue <> x.LastLocation
GROUP BY ColValue,Rn
ORDER BY Rnk DESC
)
SELECT ColDate,CX.FirstLocation,(SELECT ColValue FROM CXX) AS MidName, cx.LastLocation
FROM CX
输出:
ColDate FirstLocation MidName LastLocation
-----------------------------------------------------
2018-01-01 Location1 Location2 Location4
2018-01-02 Location1 Location2 Location4
2018-01-03 Location1 Location2 Location4
【问题讨论】:
【参考方案1】:关闭
declare @t TABLE (ColDate DATE, ColTime time, Colvalue VARCHAR(50));
INSERT INTO @t VALUES
('2018-01-01','01:10:11','Location1'),
('2018-01-01','02:10:11','Location2'),
('2018-01-01','03:10:11','Location3'),
('2018-01-01','11:10:11','Location4'),
('2018-01-02','01:10:11','Location1'),
('2018-01-02','02:10:11','Location2'),
('2018-01-02','03:10:11','Location2'),
('2018-01-02','01:10:11','Location3'),
('2018-01-02','03:15:11','Location4'),
('2018-01-03','02:10:11','Location1'),
('2018-01-03','02:50:11','Location1'),
('2018-01-03','03:10:11','Location1');
--select * from @t order by ColDate, ColTime
with cte as
( select *
, row_number() over (partition by ColDate order by ColTime asc) as tasc
, row_number() over (partition by ColDate order by ColTime desc) as tdsc
from @t
)
select distinct
cteMin.ColDate, cteMin.ColTime
, cteMin.Colvalue as [cteMin.Colvalue]
, cteMid.Colvalue as [cteMid.Colvalue]
, cteMax.Colvalue as [cteMax.Colvalue]
from cte cteMin
join cte cteMax
on cteMin.ColDate = cteMax.ColDate
and cteMin.tasc = 1
and cteMax.tdsc = 1
left join cte cteMid
on cteMid.ColDate = cteMin.ColDate
and cteMid.tasc > 1
and cteMid.tdsc = 2
and cteMid.Colvalue <> cteMin.Colvalue
and cteMid.Colvalue <> cteMax.Colvalue
【讨论】:
【参考方案2】:我会使用 correlated subquery
with apply
运算符:
select distinct t.coldate, t1.*,
( select top 1 ColValue
from TblLocation
where (coldate = t.coldate and
ColValue <> t1.FirstLocation and ColValue <> t2.LastLocation)
order by count(*) over() desc
) as MidName, t2.*
from TblLocation t cross apply
(select top 1 ColValue as FirstLocation
from TblLocation
where coldate = t.coldate
order by coltime
) t1 cross apply
(select top 1 ColValue as LastLocation
from TblLocation
where coldate = t.coldate
order by coltime desc
) t2;
【讨论】:
以上是关于SQL Server 2008 R2:使用多个 CTE 获取日期明智的记录的主要内容,如果未能解决你的问题,请参考以下文章
windows server 2008 r2 C盘空间不断减少!怎么清理
在 SQL Server 2008 R2 和 SQL Server Compact 4 中存储日期/时间数据的最佳方式