TSQL查询帮助返回缺少的行
需要以下内容的查询帮助 我有一个样本数据,如下表所示TSQL查询帮助返回缺少的行,sql,sql-server,tsql,Sql,Sql Server,Tsql,需要以下内容的查询帮助 我有一个样本数据,如下表所示 Create table #MovieShows(Id int, Movieid varchar(20), Showtime time) insert into #MovieShows values (11,'m1','13:00') insert into #MovieShows values (23,'m2','14:00') insert into #MovieShows values (34,'m1','15:00') insert
Create table #MovieShows(Id int, Movieid varchar(20), Showtime time)
insert into #MovieShows values (11,'m1','13:00')
insert into #MovieShows values (23,'m2','14:00')
insert into #MovieShows values (34,'m1','15:00')
insert into #MovieShows values (45,'m2','16:00')
insert into #MovieShows values (55,'m2','20:00')
insert into #MovieShows values (64,'m1','16:00')
insert into #MovieShows values (66,'m2','21:00')
insert into #MovieShows values (81,'m1','20:00')
go
select * from #MovieShows order by Movieid, id
==========================
Need a query to show the missing rows along with table rows.
Desired output should be
Id MovieID Showtime
11 m1 13:00
11 m1 14:00 --New row
34 m1 15:00
64 m1 16:00
64 m1 17:00 --New row
64 m1 18:00 --New row
64 m1 19:00 --New row
81 m1 20:00
23 m2 14:00
23 m2 15:00 --New row
45 m2 16:00
45 m2 17:00 --New row
45 m2 18:00 --New row
45 m2 19:00 --New row
55 m2 20:00
66 m2 21:00
查询需要显示与时间序列相关的缺失行以及表行。缺少的行需要在表行之间交错。您可以通过两个步骤执行此操作:使用交叉连接生成所有行,然后使用左连接输入值:
select m.moveid, s.showtime
from (select distinct movieid from movieshows) m cross join
(select distinct showtime from movieshows) t left join
movieshows ms
on ms.movieid = m.movieid and ms.showtime = t.showtime;
我唯一不明白的是id。如何确定不匹配行的id
嗯,这里有一种获取id的方法:
这里是另一种使用理货表的方法 首先,生成所有可能的放映时间,应该是00:00到23:00。然后获取每个电影ID的MINShowTime和MAXShowtime。现在对两个结果进行连接,以生成所有可能的电影ID和放映时间组合,使时间介于最小放映时间和最大放映时间之间 要获取Id,请使用交叉应用
如果您有SQL Server 2012或更高版本,则可以使用递归CTE并结合LEAD window函数,如下例所示:
DECLARE @MovieShows TABLE
(
Id INT, Movieid VARCHAR(20), Showtime TIME
PRIMARY KEY (Movieid, Showtime)
)
INSERT INTO @MovieShows
SELECT 11,'m1','13:00' UNION ALL
SELECT 34,'m1','15:00' UNION ALL
SELECT 64,'m1','16:00' UNION ALL
SELECT 81,'m1','21:00' UNION ALL
SELECT 23,'m2','14:00' UNION ALL
SELECT 45,'m2','16:00' UNION ALL
SELECT 55,'m2','20:00' UNION ALL
SELECT 66,'m2','21:00'
;WITH CTE_Shows
AS
(
SELECT Id
,Movieid
,Showtime
,LEAD(Showtime, 1, NULL) OVER (PARTITION BY Movieid ORDER BY Showtime) AS NextShowTime
FROM @MovieShows MovesBase
UNION ALL -- Fill in the gaps by performing a recursive union
SELECT Id
,Movieid
,DATEADD(HOUR, 1, Showtime) AS Showtime -- Add one hour to the current show time.
,Fill.NextShowTime
FROM CTE_Shows Fill
WHERE DATEADD(HOUR, 1, Fill.Showtime) < Fill.NextShowTime -- Only perform recursive union where the current show time + 1 hour is less than the next show time in the current dataset.
)
SELECT Id
,Movieid
,Showtime
FROM CTE_Shows
ORDER BY Movieid, Showtime
这种方法的主要优点是不需要额外的查找表 解决此问题的可能方法包括 临时表 自连接/交叉连接 a终止模式,以便将所有可能的显示时间存储在单独的表中,然后使用外部联接填充结果
我没有id列。如何确定不匹配行的id?您获得了CJ体验的代表;从我这里:
WITH CteHr(hr) AS(
SELECT
CAST(DATEADD(HOUR, hr, 0) AS TIME)
FROM (VALUES
(0), (1), (2), (3), (4), (5), (6), (7),
(8), (9), (10), (11), (12), (13), (14),
(15), (16), (17), (18), (19), (20), (21), (22), (23)
) AS t(hr)
),
CteMinMax(MovieId, minHr, maxHr) AS(
SELECT
MovieId, MIN(Showtime), MAX(Showtime)
FROM #MovieShows
GROUP BY MovieId
)
SELECT
t.Id,
mm.MovieId,
Showtime = h.hr
FROM CteMinMax mm
CROSS JOIN CteHr h
CROSS APPLY(
SELECT TOP 1 Id
FROM #MovieShows
WHERE
Movieid = mm.MovieId
AND Showtime <= h.hr
ORDER BY Showtime DESC
) t
WHERE h.hr BETWEEN mm.minHr AND mm.maxHr
DECLARE @MovieShows TABLE
(
Id INT, Movieid VARCHAR(20), Showtime TIME
PRIMARY KEY (Movieid, Showtime)
)
INSERT INTO @MovieShows
SELECT 11,'m1','13:00' UNION ALL
SELECT 34,'m1','15:00' UNION ALL
SELECT 64,'m1','16:00' UNION ALL
SELECT 81,'m1','21:00' UNION ALL
SELECT 23,'m2','14:00' UNION ALL
SELECT 45,'m2','16:00' UNION ALL
SELECT 55,'m2','20:00' UNION ALL
SELECT 66,'m2','21:00'
;WITH CTE_Shows
AS
(
SELECT Id
,Movieid
,Showtime
,LEAD(Showtime, 1, NULL) OVER (PARTITION BY Movieid ORDER BY Showtime) AS NextShowTime
FROM @MovieShows MovesBase
UNION ALL -- Fill in the gaps by performing a recursive union
SELECT Id
,Movieid
,DATEADD(HOUR, 1, Showtime) AS Showtime -- Add one hour to the current show time.
,Fill.NextShowTime
FROM CTE_Shows Fill
WHERE DATEADD(HOUR, 1, Fill.Showtime) < Fill.NextShowTime -- Only perform recursive union where the current show time + 1 hour is less than the next show time in the current dataset.
)
SELECT Id
,Movieid
,Showtime
FROM CTE_Shows
ORDER BY Movieid, Showtime