【问题标题】:Nested subqueries with ROW_NUMBER logic problem具有 ROW_NUMBER 逻辑问题的嵌套子查询
【发布时间】:2019-04-22 15:21:45
【问题描述】:

(SQL Server 2008) 我正在尝试从工厂计时系统中过滤掉人工记录。这是下面的数据示例。TCODE 列有一个“O”(开启时间)或一个“OF”(关闭时间)。因此,例如 CHAVEZ 在序列 50(kitpull)上工作了 1.06 小时。

问题:当工作人员完成超过 2 次滑动的作业序列时,系统会自动添加我需要删除的最后一对开关记录(0 小时)。在序列 50 Pull Kit 和序列 400 Countersinking 的情况下,只有两次滑动(打开,然后关闭),因此没有额外的记录。但是,其他每个序列都有两个尾随的额外行。在序列 100 的情况下,TTIME=93724 (09:37:24 AM) 的最后两行是额外的行。您可以看到最后一行的完整代码 1 正式标记作业序列已完成。

MFGORDNO  SEQUENCE  DESCR                 BADGE  LABOR  TCODE  ENAME   TTIME  CompleteCode
M968460   50        Pull Kit              802    0.00   O      CHAVEZ  82300  NULL
M968460   50        Pull Kit              802    1.06   OF     CHAVEZ  92631  0
M968460   100       Load Parts into AJ    396    0.00   O      CURNEY  150014 NULL
M968460   100       Load Parts into AJ    396    1.00   OF     CURNEY  160022 0
M968460   100       Load Parts into AJ    3169   0.00   O      JONES   84612  NULL
M968460   100       Load Parts into AJ    3169   0.85   OF     JONES   93724  0
M968460   100       Load Parts into AJ    3169   0.00   O      JONES   93724  NULL
M968460   100       Load Parts into AJ    3169   0.00   OF     JONES   93724  1
M968460   200       Transfer Drill Holes  3169   0.00   O      JONES   93737  NULL
M968460   200       Transfer Drill Holes  3169   2.73   OF     JONES   132135 0
M968460   200       Transfer Drill Holes  3169   0.00   O      JONES   132135 NULL
M968460   200       Transfer Drill Holes  3169   0.00   OF     JONES   132135 1
M968460   300       TransDrill Splices    3169   0.00   O      JONES   132153 NULL
M968460   300       TransDrill Splices    3169   3.56   OF     JONES   65539  0
M968460   300       TransDrill Splices    3169   0.00   O      JONES   65539  NULL
M968460   300       TransDrill Splices    3169   0.01   OF     JONES   65539  1
M968460   400       Countersinking        3169   0.00   O      JONES   63102  NULL
M968460   400       Countersinking        3169   2.79   OF     JONES   91716  0
M968460   600       SPLICE STRAPS         3169   0.00   O      JONES   131931 NULL
M968460   600       SPLICE STRAPS         3169   1.17   OF     JONES   143040 0
M968460   600       SPLICE STRAPS         3169   0.00   O      JONES   63456  NULL
M968460   600       SPLICE STRAPS         3169   4.12   OF     JONES   105200 0
M968460   600       SPLICE STRAPS         3169   0.00   O      JONES   105200 NULL
M968460   600       SPLICE STRAPS         3169   0.00   OF     JONES   105200 1

期望的结果:简而言之,我正在尝试使用单个 SQL 语句来获得这个结果数据。

MFGORDNO  SEQUENCE  DESCR                 BADGE  LABOR  TCODE  ENAME   TTIME  CompleteCode
M968460   50        Pull Kit              802    0.00   O      CHAVEZ  82300  NULL
M968460   50        Pull Kit              802    1.06   OF     CHAVEZ  92631  0
M968460   100       Load Parts into AJ    396    0.00   O      CURNEY  150014 NULL
M968460   100       Load Parts into AJ    396    1.00   OF     CURNEY  160022 0
M968460   100       Load Parts into AJ    3169   0.00   O      JONES   84612  NULL
M968460   100       Load Parts into AJ    3169   0.85   OF     JONES   93724  0
M968460   200       Transfer Drill Holes  3169   0.00   O      JONES   93737  NULL
M968460   200       Transfer Drill Holes  3169   2.73   OF     JONES   132135 0
M968460   300       TransDrill Splices    3169   0.00   O      JONES   132153 NULL
M968460   300       TransDrill Splices    3169   3.56   OF     JONES   65539  0
M968460   400       Countersinking        3169   0.00   O      JONES   63102  NULL
M968460   400       Countersinking        3169   2.79   OF     JONES   91716  0
M968460   600       SPLICE STRAPS         3169   0.00   O      JONES   131931 NULL
M968460   600       SPLICE STRAPS         3169   1.17   OF     JONES   143040 0
M968460   600       SPLICE STRAPS         3169   0.00   O      JONES   63456  NULL
M968460   600       SPLICE STRAPS         3169   4.12   OF     JONES   105200 0

我最初开始向最里面的子查询添加一个行号,以便稍后可以像这样引用 MAX(rn):

SELECT
    *, 
    ROW_NUMBER() OVER (ORDER by TTIME) rn 
FROM
    MySmallData

从上面的子查询中,我希望从原始数据中选择所有记录,删除“CompleteCode 中为 1 的行和正上方的行”。

这更像是一个策略问题而不是语法问题。我希望得到一些建议。

谢谢, 约翰

编辑:抱歉,这里有一些示例数据:

CREATE TABLE MySmallData 
(
    [MFGORDNO] NVARCHAR(7),
    [SEQUENCE] INT,
    [DESCR] NVARCHAR(20),
    [BADGE] INT,
    [LABOR] NUMERIC(3, 2),
    [TCODE] NVARCHAR(2),
    [TSTAMP] NVARCHAR(26),
    [ENAME] NVARCHAR(19),
    [TTIME] INT,
    [CompleteCode] INT
);

INSERT INTO MySmallData 
VALUES
    ('M968460',0050,'Pull Kit',802,0,'O','2019-02-26 08:23:00.000004','CHAVEZ',82300,NULL),
    ('M968460',0050,'Pull Kit',802,1.06,'OF','2019-02-26 09:26:30.999995','CHAVEZ',92631,0),
    ('M968460',0100,'Load Parts into AJ',396,0,'O','2019-03-05 15:00:13.999997','CURNEY',150014,NULL),
    ('M968460',0100,'Load Parts into AJ',396,1,'OF','2019-03-05 16:00:22.000001','CURNEY',160022,0),
    ('M968460',0100,'Load Parts into AJ',3169,0,'O','2019-03-06 08:46:12.000003','JONES',84612,NULL),
    ('M968460',0100,'Load Parts into AJ',3169,0.85,'OF','2019-03-06 09:37:23.999998','JONES',93724,0),
    ('M968460',0100,'Load Parts into AJ',3169,0,'O','2019-03-06 09:37:23.999998','JONES',93724,NULL),
    ('M968460',0100,'Load Parts into AJ',3169,0,'OF','2019-03-06 09:37:23.999998','JONES',93724,1),
    ('M968460',0200,'Transfer Drill Holes',3169,0,'O','2019-03-06 09:37:37.000001','JONES',93737,NULL),
    ('M968460',0200,'Transfer Drill Holes',3169,2.73,'OF','2019-03-06 13:21:35.000001','JONES',132135,0),
    ('M968460',0200,'Transfer Drill Holes',3169,0,'O','2019-03-06 13:21:35.000001','JONES',132135,NULL),
    ('M968460',0200,'Transfer Drill Holes',3169,0,'OF','2019-03-06 13:21:35.000001','JONES',132135,1),
    ('M968460',0300,'TransDrill Splices',3169,0,'O','2019-03-06 13:21:52.999998','JONES',132153,NULL),
    ('M968460',0300,'TransDrill Splices',3169,3.56,'OF','2019-03-06 16:55:39','JONES',165539,0),
    ('M968460',0300,'TransDrill Splices',3169,0,'O','2019-03-06 16:55:39','JONES',165539,NULL),
    ('M968460',0300,'TransDrill Splices',3169,0.01,'OF','2019-03-06 16:55:39','JONES',165539,1),
    ('M968460',0400,'Countersinking',3169,0,'O','2019-03-07 06:31:01.999998','JONES',63102,NULL),
    ('M968460',0400,'Countersinking',3169,2.79,'OF','2019-03-07 09:17:15.999996','JONES',91716,0),
    ('M968460',0600,'SPLICE STRAPS',3169,0,'O','2019-03-08 13:19:30.999999','JONES',131931,NULL),
    ('M968460',0600,'SPLICE STRAPS',3169,1.17,'OF','2019-03-08 14:30:39.999997','JONES',143040,0),
    ('M968460',0600,'SPLICE STRAPS',3169,0,'O','2019-03-12 06:34:56.000003','JONES',63456,NULL),
    ('M968460',0600,'SPLICE STRAPS',3169,4.12,'OF','2019-03-12 10:52:00.000002','JONES',105200,0),
    ('M968460',0600,'SPLICE STRAPS',3169,0,'O','2019-03-12 10:52:00.000002','JONES',105200,NULL),
    ('M968460',0600,'SPLICE STRAPS',3169,0,'OF','2019-03-12 10:52:00.000002','JONES',105200,1);

【问题讨论】:

    标签: sql-server subquery


    【解决方案1】:

    我认为你可以使用exists

    select msd.*
    from mysmalldata msd
    where not ((msd.completecode is null and
                exists (select 1
                        from mysmalldata msd2
                        where msd2.MFGORDNO = msd.MFGORDNO and
                              msd2.sequence = msd.sequence and
                              msd2.badge = msd.badge and
                              msd2.ttime = msd.ttime and
                              msd2.completecode = 1
                       )
                ) or
               (coalesce(msd.completecode, -1) = 1 and
                exists (select 1
                        from mysmalldata msd2
                        where msd2.MFGORDNO = msd.MFGORDNO and
                              msd2.sequence = msd.sequence and
                              msd2.badge = msd.badge and
                              msd2.ttime = msd.ttime and
                              msd2.completecode is null
                       )
                )
               );   
    

    Here 是一个 dbfiddle。

    【讨论】:

    • 感谢@Gordon Linoff。是的,这就是我遇到麻烦的地方。以上仅返回 CompleteCode = 0 的记录。它删除了所有空行。仅应删除与 CompleteCode = 1 行配对的空行。其他空行需要保留在结果中。
    • @JohnJoseph 。 . .这是我很长一段时间以来不得不发现的更微妙的错误之一。 OR 的第二个条件是返回 NULL,而 completecodeNULL。这导致整个表达式为 NULL 并被过滤掉。我已经替换了逻辑。
    【解决方案2】:

    开始制作我自己的版本,想“不,选择@Gordon,他是怎么做到的”,遇到了一些问题,所以接受它 (+1) 并对其进行了一些修改:

    SELECT msd.*
     from mysmalldata msd
     where msd.completecode = 0  --  All "completeCode=0" rows are accepted
      or (--  All "NULL" rows for which there is no matching "completeCode=1" row are accepted
          msd.completecode is null
           and not exists (select 1
                            from mysmalldata msd2
                             where msd2.MFGORDNO = msd.MFGORDNO
                              and msd2.sequence = msd.sequence
                              and msd2.badge = msd.badge
                              and msd2.ttime = msd.ttime
                              and msd2.completecode = 1
                          )
         )
     --  Note that no "completeCode=1" rows are accepted
    

    【讨论】:

    • @PhillipKelley 也很棒。不错的减法。感谢您的帮助
    • 未来读者:@Gordon 已经根据我的修改修改了他的代码。一种价格的两种可能的解决方案!
    猜你喜欢
    • 2016-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多