在sql中迭代行时发现不匹配

时间:2013-05-10 20:40:38

标签: sql sql-server

我有这个问题,其中日期键只是通过SQL Server插入表中。它们以下面显示的方式迭代填充:

  • 20130501
  • 20130502
  • 20130503
  • ...

我目前正试图找到其中一个日期被跳过的任何行,即:

  • 20130504
  • 20130506
  • 20130507

我仍然是SQL Server的新手,我看过CURSOR,但是我在理解如何查询这个问题时遇到了一些麻烦。任何帮助,将不胜感激。感谢。

2 个答案:

答案 0 :(得分:0)

SELECT *
FROM table
WHERE date - 1 NOT IN (SELECT date FROM table)

这可能不是超级有效但它应该有用。

答案 1 :(得分:0)

使用Itzik Ben-Gan学派的一些技巧。找到差距的最简单方法是使用计数表。这是一种在表变量中创建一个小表的方法,但我建议创建一个经过证实的Numbers表,因为它们对于这种事情非常方便。您可以找到一些关于如何执行此操作的示例here

首先创建一个数字表

DECLARE @Numbers TABLE ( [Number] INT );

    INSERT  INTO @Numbers
    (
      Number
    )
    SELECT TOP 1000
            ROW_NUMBER() OVER (ORDER BY [s1].[object_id]) AS Number
    FROM    sys.objects s1
    CROSS JOIN sys.objects s2

接下来我需要创建一个临时表来重新创建您的示例

DECLARE @ExampleDates TABLE ( [RecordDateKey] INT );

INSERT  INTO @ExampleDates
    ( [RecordDateKey] )
VALUES  ( 20130501 ),
        ( 20130502 ),
        ( 20130503 ),
        ( 20130504 ),
        ( 20130506 ),
        ( 20130507 ),
        ( 20130508 ),
        ( 20130511 );

这种语法仅适用于2008-r2和转发,但由于我只是暂存数据,所以这并不是什么大问题。只需将此笔记留给测试此示例的其他人。

最后我们需要做一些转换工作。

对于较大的集合,证实这些数据可能是有益的,但对于这个小例子,cte就足够了。

WITH    date_convert
      AS (
           SELECT   [RecordDateKey]
                  , CONVERT(DATETIME, CAST([RecordDateKey] AS VARCHAR(50)), 112) [RecordDate]
           FROM     @ExampleDates ed
         ) ,
    date_range
      AS (
           SELECT   DATEDIFF(DAY, MIN([RecordDate]), MAX([RecordDate])) [Range]
                  , MIN([RecordDate]) [StartDate]
           FROM     [date_convert]
         ) ,
    all_dates
      AS (
           SELECT   CONVERT(INT, CONVERT(VARCHAR(8), DATEADD(DAY, num.[Number], [StartDate]), 112)) AS [RecordDateKey]
                  , DATEADD(DAY, num.[Number], [StartDate]) [RecordDate]
           FROM     @Numbers num
           CROSS JOIN [date_range] dr
           WHERE    num.[Number] <= dr.[Range]
         )
 SELECT [RecordDateKey]
      , [RecordDate]
 FROM   all_dates ad
 WHERE  NOT EXISTS ( SELECT 1
                     FROM   [date_convert] dc
                     WHERE  ad.[RecordDate] = dc.RecordDate )
  • date_convert:将您提供的密钥更改为日期时间以便于比较和dateadd。

  • date_range:查找日期范围以及范围开始的位置。

  • all_dates:查找您所在范围内应存在的所有日期。

  • 最终选择查找数据中不在生成集中的记录。

使用此代码,这是我的输出。无论间隙大小如何,都应找到间隙。这似乎是当前接受的答案的问题。

RecordDateKey   RecordDate
-------------   ----------
20130505        2013-05-05 00:00:00.000
20130509        2013-05-09 00:00:00.000
20130510        2013-05-10 00:00:00.000