【问题标题】:Finding missing sequence number in SQL 2008 table在 SQL 2008 表中查找缺失的序列号
【发布时间】:2018-05-17 06:44:35
【问题描述】:

我有一个通过此查询返回以下内容的表:

SELECT *    
  FROM [PROC_MN]    
  where PO_NO='GV17885' AND DOC_NO='622843' 

ID  PO_NO   DOC_NO  PROCESS_SEQ PROCESS_NAME    STATUS  TIME
756 GV17885 622843  2   R.M.Requisition Start   23-04-18 15:29
788 GV17885 622843  2   R.M.Requisition Finish  23-04-18 15:50
289 GV17885 622843  1   CTP Start   23-04-18 8:57
426 GV17885 622843  1   CTP Finish  23-04-18 10:09
901 GV17885 622843  3   Material Cut    Start   23-04-18 17:23
903 GV17885 622843  3   Material Cut    Finish  23-04-18 17:26
1669    GV17885 622843  4   Print   Start   24-04-18 13:59
1712    GV17885 622843  4   Print   Finish  24-04-18 14:44
3421    GV17885 622843  5   Q.C Start   27-04-18 8:04
3492    GV17885 622843  5   Q.C Finish  27-04-18 8:42
3630    GV17885 622843  7   RFID    Start   27-04-18 9:36
3632    GV17885 622843  7   RFID    Finish  27-04-18 9:38
4264    GV17885 622843  8   Q.C Start   27-04-18 14:58
4288    GV17885 622843  8   Q.C Finish  27-04-18 15:16
4729    GV17885 622843  9   Encode  Start   28-04-18 8:48
4734    GV17885 622843  9   Encode  Finish  28-04-18 8:49
4698    GV17885 622843  9   Encode  Start   28-04-18 8:24
4722    GV17885 622843  9   Encode  Finish  28-04-18 8:47
5016    GV17885 622843  10  Q.C Start   28-04-18 13:38
5073    GV17885 622843  10  Q.C Finish  28-04-18 14:11

我想找到丢失的 PROCESS_SEQ 行,通过上面的结果我们发现丢失的 PROCESS_SEQ 是数字 6 。我使用以下查询,但它什么也不返回/。请帮忙!

SET NOCOUNT ON;

DECLARE @Min BIGINT
DECLARE @Max BIGINT
DECLARE @i BIGINT

IF OBJECT_ID('tempdb..#TempTable') 不为空 开始 删除表#TempTable 结束

CREATE TABLE #TempTable
    (
      TempOrderNumber BIGINT
    )

SELECT  @Min = ( SELECT MIN([PROCESS_SEQ])
                 FROM   [PROC_MN] WITH ( NOLOCK )
                 WHERE PO_NO='GV17885' AND [DOC_NO]='622843')
SELECT  @Max = ( SELECT MAX([PROCESS_SEQ])
                 FROM   [PROC_MN] WITH ( NOLOCK )
                 WHERE PO_NO='GV17885' AND [DOC_NO]='622843')
SELECT  @i = @Min

WHILE @i <= @Max 
    BEGIN
        INSERT  INTO #TempTable
                SELECT  @i

        SELECT  @i = @i + 1

    END

SELECT  TempOrderNumber
FROM    #TempTable
        LEFT JOIN [PROC_MN] o WITH ( NOLOCK ) ON tempordernumber = o.[PROCESS_SEQ]
WHERE   o.[PROCESS_SEQ] IS NULL 

【问题讨论】:

  • 您需要一次丢失所有的数字吗?还是只是第一个?
  • 我需要 PO_NO= 中所有缺失的序列号吗? AND [DOC_NO]=?

标签: sql-server-2008


【解决方案1】:

您可以尝试以下查询:

WITH
    [MISSING_RANGES] AS
    (
        SELECT
            [MISSING_RANGE_NO] = ROW_NUMBER() OVER (ORDER BY P.[PO_NO], P.[DOC_NO], P.[PROCESS_SEQ]),
            P.[PO_NO],
            P.[DOC_NO],
            [FIRST_MISSING] = P.[PROCESS_SEQ] + 1,
            [LAST_MISSING] = N.[PROCESS_SEQ] - 1
        FROM
            [PROC_MN] AS P
            OUTER APPLY (SELECT [PROCESS_SEQ] = MIN([PROCESS_SEQ])
                         FROM [PROC_MN]
                         WHERE
                             [PO_NO] = P.[PO_NO] AND
                             [DOC_NO] = P.[DOC_NO] AND
                             [PROCESS_SEQ] > P.[PROCESS_SEQ]) AS N
        WHERE
            N.[PROCESS_SEQ] > P.[PROCESS_SEQ] + 1
    ),
    [MISSING_SEQUENCES] AS
    (
        SELECT
            [MISSING_RANGE_NO],
            [MISSING_PROCESS_SEQ] = [FIRST_MISSING]
        FROM
            [MISSING_RANGES]
    UNION ALL
        SELECT
            R.[MISSING_RANGE_NO],
            S.[MISSING_PROCESS_SEQ] + 1
        FROM
            [MISSING_RANGES] AS R
            INNER JOIN [MISSING_SEQUENCES] AS S ON S.[MISSING_RANGE_NO] = R.[MISSING_RANGE_NO]
        WHERE
            S.[MISSING_PROCESS_SEQ] < R.[LAST_MISSING]
    )
SELECT DISTINCT
    R.[PO_NO],
    R.[DOC_NO],
    S.[MISSING_PROCESS_SEQ]
FROM
    [MISSING_RANGES] AS R
    INNER JOIN [MISSING_SEQUENCES] AS S ON S.[MISSING_RANGE_NO] = R.[MISSING_RANGE_NO]
--WHERE
--    R.[PO_NO] = ? AND
--    R.[DOC_NO] = ?
ORDER BY
    R.[PO_NO],
    R.[DOC_NO],
    S.[MISSING_PROCESS_SEQ]
OPTION (MAXRECURSION 10000);

(出于测试目的,我将 WHERE 子句用于过滤特定的 [PO_NO] AND [DOC_NO] 值。)

编辑(响应额外更新的帖子):

这是我个人版本的 SQL 脚本。就像你的一样,它会生成一个包含序列(从最小值到最大值)的临时表,并选择数据表中的记录无法连接的所有值:

DECLARE @PO_NO VARCHAR(10) = 'GV17885';
DECLARE @DOC_NO VARCHAR(10) = '622843';

DECLARE @TempTable TABLE
(
    [TempOrderNumber] BIGINT PRIMARY KEY
);

DECLARE @Min BIGINT;
DECLARE @Max BIGINT;

SELECT
    @Min = MIN([PROCESS_SEQ]),
    @Max = MAX([PROCESS_SEQ])
FROM
    [PROC_MN] WITH (NOLOCK)
WHERE
    [PO_NO] = @PO_NO AND
    [DOC_NO] = @DOC_NO;

DECLARE @i BIGINT = @Min;

WHILE (@i <= @Max) BEGIN
    INSERT INTO @TempTable ([TempOrderNumber])
    SELECT @i;

    SET @i += 1;
END;

SELECT
    [TempOrderNumber]
FROM
    @TempTable
    LEFT JOIN [PROC_MN] AS O WITH (NOLOCK) ON
        [TempOrderNumber] = O.[PROCESS_SEQ]
        AND O.[PO_NO] = @PO_NO
        AND O.[DOC_NO] = @DOC_NO
WHERE
    O.[PROCESS_SEQ] IS NULL;

这也应该可以正常工作。但我个人更喜欢我原来的查询,因为它是基于集合操作而不是循环。

【讨论】:

  • 不返回任何内容,请查看我的 EDITED 查询,但它仍然不返回任何内容。
  • 我会看看你的更新。但是,在没有 WHERE 子句的情况下在 SQL Server Management Studio 中执行时,它是否也不返回任何内容? (我用一个示例表对其进行了测试(包含三个使用字段的虚拟值,效果很好。)
  • 使用上面的示例数据,我使用了您的查询,但它什么也没返回。不知道为什么?
  • 很奇怪。我再次对其进行了测试,这次是使用您的特定数据样本。然后它生成两条相同的记录,均缺少值 6。(可能是因为始终存在两条具有相同值的 [PO_NO]、[DOC_NO] 和 [PROCESS_SEQ] 的记录:一条状态为“开始”,一条状态为“完成” '。所以我的查询可能需要在 SELECT 子句中添加一个额外的 DISTINCT。)我不知道(还)为什么它不会在您的数据库中返回任何结果...
  • 我查看了您更新的帖子。应该管用。几乎。一个细节。您可能还想在最终连接中过滤正确的 [PO_NO] 和 [DOC_NO] 值。然后它也会给出正确的结果。
猜你喜欢
  • 2010-11-06
  • 2020-05-26
  • 1970-01-01
  • 1970-01-01
  • 2021-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多