TSQL查询有助于返回缺失的行

时间:2016-05-11 01:10:47

标签: 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 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 

查询需要显示与时间序列相关的缺失行以及表行。丢失的行需要在表行之间进行交错。

4 个答案:

答案 0 :(得分:2)

您可以分两步执行此操作:使用cross join生成所有行,然后left join放入值:

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的一种方式:

select ms.id, m.moveid, s.showtime
from (select distinct movieid from movieshows) m cross join
     (select distinct showtime from movieshows) t outer apply
     (select top 1 ms.*
      from movieshows ms
      where ms.movieid = m.movieid and ms.showtime <= t.showtime
      order by ms.showtime desc
     ) ms

答案 1 :(得分:0)

这是使用Tally Table的另一种方法。

首先,生成所有可能的ShowTime,其应为00:0023:00。然后获取每个MIN(ShowTime)的{​​{1}}和MAX(Showtime)。现在对两个结果执行MovieId以生成JOINMovieId的所有可能组合,以便时间介于ShowtimeMIN {{之间1}}。

要获取MAX,请使用Showtime

Id

ONLINE DEMO

答案 2 :(得分:0)

如果你有SQL Server 2012或更高版本,你可以使用递归CTE结合LEAD窗口函数,如下例所示:

    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

此方法的主要优点是无需额外的查找表。

答案 3 :(得分:0)

解决此问题的可能方法包括

  1. 临时表

  2. 自/交叉联接

  3. 修改架构,以便将所有可能的放映时间存储在单独的表中,然后使用外部联接填充结果。