【问题标题】:sql select min or max based on condition part 2sql 根据条件选择最小值或最大值第 2 部分
【发布时间】:2015-10-31 02:29:24
【问题描述】:

这个帖子是另一个帖子sql select min or max based on condition的问题的延续

我正在尝试根据各种条件获得一行。

场景 1 - 如果不存在小时数(setup + processtime > 0),则获取最高行。

场景 2 -如果有几个小时(如本例所示),则在此数字之后显示下一个操作 (oprnum)。 (prodroute 中为 60)。

查询需要在 CTE 中工作,因为它是更大查询的一部分。

    CREATE TABLE ProdRoute
    ([ProdId] varchar(10), [OprNum] int, [SetupTime] int, [ProcessTime] numeric)
;

INSERT INTO ProdRoute
    ([ProdId], [OprNum], [SetupTime], [ProcessTime])
VALUES
    ('12M0004893', 12, 0.7700000000000000, 1.2500000000000000),
    ('12M0004893', 12, 0.0000000000000000, 0.0000000000000000),
    ('12M0004893', 40, 0.0800000000000000, 0.4000000000000000),
    ('12M0004893', 50, 0.0400000000000000, 2.8000000000000000),
    ('12M0004893', 50, 0.0000000000000000, 0.0000000000000000),
    ('12M0004893', 60, 0.0000000000000000, 0.6100000000000000),
    ('12M0004893', 60, 0.0000000000000000, 0.0000000000000000),
    ('12M0004893', 70, 0.0000000000000000, 1.2900000000000000),
    ('12M0004893', 70, 0.0000000000000000, 0.0000000000000000),
    ('12M0004893', 75, 0.0000000000000000, 3.8700000000000000),
    ('12M0004893', 75, 0.0000000000000000, 0.0000000000000000),
    ('12M0004893', 80, 0.0000000000000000, 0.5500000000000000),
('12M0003571', 3, 0.8900000000000000, 0.0000000000000000),
    ('12M0003571', 3, 0.0000000000000000, 0.0000000000000000),
    ('12M0003571', 7, 1.0000000000000000, 0.0000000000000000),
    ('12M0003571', 10, 0.3000000000000000, 0.3000000000000000),
    ('12M0003571', 10, 0.0000000000000000, 0.0000000000000000),
    ('12M0003571', 20, 0.0700000000000000, 0.1000000000000000),
    ('12M0003571', 20, 0.0000000000000000, 0.0000000000000000),
    ('12M0003571', 30, 0.0000000000000000, 0.0000000000000000),
    ('12M0003571', 40, 0.0000000000000000, 0.0000000000000000),
    ('12M0003571', 50, 0.0000000000000000, 0.0000000000000000),
    ('12M0003571', 60, 0.0000000000000000, 0.0000000000000000),
    ('12M0003571', 60, 0.0000000000000000, 0.0000000000000000),
    ('12M0003571', 70, 0.0700000000000000, 0.1500000000000000),
    ('12M0003571', 70, 0.0000000000000000, 0.0000000000000000)
;

CREATE TABLE ProdRouteTran
    ([ProdID] varchar(10), [MaxOpCompleted] int, [Hours] numeric)
;

INSERT INTO ProdRouteTran
    ([ProdID], [MaxOpCompleted], [Hours])
VALUES
    ('12M0004893', 50, 1.7800000000000000),
('12M0003571', 70, 1.2660000000000000)
;

预期输出:

ProdId  OprNum
12M0004893  60

ProdId  OprNum
12M0003571  70

【问题讨论】:

    标签: sql sql-server tsql sql-server-2012


    【解决方案1】:

    根据新数据和提问者对答案的最后评论,这是更新后的查询和小提琴:http://sqlfiddle.com/#!6/87e2f/2

    嘿,我发现了一个不起作用的示例... orderID '12M0003381'... 我已将数据添加到您的小提琴中。我希望看到操作 70 为 这是最后一次设置或处理时间的操作...谢谢!

    select prodid, ISNULL(MAX(weighted_value),MIN(oprnum)) as value from
    (           
                select 
                    a.prodid,
                    a.oprnum,
                    ISNULL(LEAD(a.oprnum,1) OVER(Partition by a.prodID  ORDER by a.oprnum asc),a.oprnum)  * 
                    MAX(case 
                        when ISNULL([Hours], 0) >= (setupTime + ProcessTime) AND (SetupTime + ProcessTime ) > 0 
                        then 1
                        else NULL
                        end) as weighted_value
                from temp1 a LEFT JOIN temp4 b 
                        ON a.OprNum = b.OPRNUM
                        AND a.ProdID = b.ProdId
                group by a.prodid,a.oprnum
    ) t
    group by prodid
    

    以下查询更改的说明:

    对查询所做的唯一更改是使用以下语法处理 weighted_valueNULL

    ISNULL(LEAD(a.oprnum,1) OVER(Partition by a.prodID  ORDER by a.oprnum asc),a.oprnum)
    

    有问题的部分是内部查询,当没有 group by 子句运行时,它会显示在用户添加的边界情况下发生的情况。

    (请参见此处的小提琴:http://sqlfiddle.com/#!6/87e2f/3

    如果不处理空值,我们有一个NULL,在group by 子句之后会产生如下结构

    (请在此处查看小提琴:http://sqlfiddle.com/#!6/87e2f/5

    正如您在将 prodid : 12M0003381, oprnum:70 的 LEAD 值分组时看到的那样,结果为 NULL 而不是 70(因为分组 70NULL 应该给出 70)。

    如果 LEAD 是在分组查询/表上计算的,这是合理的,这实际上就是这里发生的事情。

    在这种情况下,LEAD 函数将不会返回分区最后一行的任何数据。这是边界情况,必须使用ISNULL 正确处理。

    我假设最后一行的LEAD oprnum 值应该被更正为当前行的oprnum 值。

    下面的旧答案:

    所以我尝试并发布了小提琴链接 http://sqlfiddle.com/#!6/e965c/1

    select prodid, ISNULL(MAX(weighted_value),MIN(oprnum)) as value from 
    ( 
    select 
    a.prodid, 
    a.oprnum, 
    LEAD(a.oprnum,1) OVER(Partition by a.prodID ORDER by a.oprnum asc) * 
    MAX(case 
    when ISNULL([Hours], 0) >= (setupTime + ProcessTime) AND (SetupTime + ProcessTime ) > 0 
    then 1 
    else NULL 
    end) as weighted_value 
    from ProdRoute a LEFT JOIN COMPLETED_OP b 
    ON a.OprNum = b.OPRNUM 
    AND a.ProdID = b.ProdId 
    group by a.prodid,a.oprnum 
    ) t 
    group by prodid
    

    【讨论】:

      【解决方案2】:

      这不是我写过的最漂亮的东西,但它确实有效。我还用其他数据对它进行了测试。

      已修改以满足新要求。

      SELECT
          *
      FROM
          (
              SELECT
                  A.ProdID,
                  MIN(A.OprNum) AS 'OprNum'
              FROM
                  #ProdRoute AS A
                  JOIN 
                      (
                          SELECT
                              ProdID,
                              MAX(MaxOpCompleted) AS 'OprNum'
                          FROM
                              #ProdRouteTran
                          GROUP BY
                              ProdID
                      ) AS B
                      ON A.ProdId = B.ProdId AND A.OprNum > B.OprNum
              GROUP BY
                  A.ProdID
          ) AS [HoursA]
      UNION ALL
      SELECT
          *
      FROM
          (
              SELECT
                  DISTINCT
                  A.ProdID,
                  B.OprNum
              FROM
                  #ProdRoute AS A
                  JOIN 
                      (
                          SELECT
                              ProdID,
                              MAX(MaxOpCompleted) AS 'OprNum'
                          FROM
                              #ProdRouteTran
                          GROUP BY
                              ProdID
                      ) AS B
                      ON A.ProdId = B.ProdId AND A.OprNum = B.OprNum
                          AND B.OprNum = (SELECT MAX(OprNum) FROM #ProdRoute WHERE ProdId = A.ProdId)
          ) AS [HoursB]
      UNION ALL
      SELECT
          *
      FROM
          (
              SELECT
                  ProdId,
                  MIN(OprNum) AS 'OprNum'
              FROM
                  #ProdRoute
              WHERE
                  ProdId NOT IN 
                      (SELECT ProdId FROM #ProdRouteTran)
                  AND (SetupTime <> 0 OR ProcessTime <> 0)
              GROUP BY
                  ProdId
          ) AS [NoHoursA]
      UNION ALL
      SELECT
          *
      FROM
          (
              SELECT
                  ProdId,
                  MIN(OprNum) AS 'OprNum'
              FROM
                  #ProdRoute
              WHERE
                  ProdId NOT IN 
                      (SELECT ProdId FROM #ProdRouteTran)
              GROUP BY
                  ProdId
              HAVING
                  SUM(SetupTime) = 0 AND SUM(ProcessTime) = 0
          ) AS [NoHoursB]
      

      【讨论】:

        【解决方案3】:

        我不确定我是否理解你的问题,但这是我的尝试:

        SELECT
            pr.ProdId,
            CASE 
                WHEN SUM(SetupTime) + SUM(ProcessTime) > 0 THEN MAX(x.OprNum)
                ELSE MAX(pr.OprNum)
            END
        FROM ProdRoute pr
        INNER JOIN (
            SELECT ProdID, MAX(MaxOpCompleted) AS OprNum
            FROM ProdRouteTran
            GROUP BY ProdID
        )prt
            ON prt.ProdId = pr.ProdID
            AND prt.OprNum = pr.OprNum
        OUTER APPLY(
            SELECT TOP 1 OprNum FROM ProdRoute 
            WHERE 
                ProdId = pr.ProdId
                AND OprNum > pr.OprNum
            ORDER BY OprNum
        )x
        GROUP BY pr.ProdId
        ORDER BY pr.ProdId
        

        【讨论】:

          【解决方案4】:

          试试这个 -

          -- display the next operation, if condition match
          SELECT do_exists.ProdId, do_exists.OprNum
          FROM ProdRoute pr
          INNER JOIN ProdRouteTran prt 
              ON prt.ProdId = pr.ProdId 
              AND pr.OprNum = prt.MaxOpCompleted 
              AND (pr.SetupTime + pr.ProcessTime) > 0
          OUTER APPLY (
              SELECT TOP(1) pr.* 
              FROM ProdRoute pr
              WHERE prt.ProdID = pr.ProdId
              AND   pr.OprNum > prt.MaxOpCompleted
              ORDER BY pr.OprNum
          ) do_exists
          
          
          UNION ALL
          
          -- display the max operation, if matching data is not found in ProdRoute. 
          ---- Matching Data not found - 1) There is entry in ProdRoute for particular ProdId but hours is not present
          ----                           2) There is no entry in ProdRoute for a particular ProdId    
          SELECT pr.ProdId, MAX(pr.OprNum) OprNum
          FROM ProdRoute pr
          LEFT JOIN (
              SELECT pr.ProdId
              FROM ProdRoute pr
              INNER JOIN ProdRouteTran prt 
                  ON prt.ProdId = pr.ProdId 
                  AND pr.OprNum = prt.MaxOpCompleted 
                  AND (pr.SetupTime + pr.ProcessTime) > 0
          ) pr_ex ON pr_ex.ProdId = pr.ProdId
          WHERE pr_ex.ProdId IS NULL 
          GROUP BY pr.ProdId
          

          【讨论】:

            【解决方案5】:

            我用这个SQL Fiddle 得到了正确的结果。

            但是我不确定我是否完全理解 nothing &gt;0 的情况。包含所有案例的更多数据可能会有用。

            ; With data as (
                Select r.ProdId
                , opr = case when h > 0 then  isnull(min(p.OprNum), r.OprNum) else  max(p.OprNum) end
                From (
                    Select pr.ProdId, pr.OprNum, h = max(pr.SetupTime + pr.ProcessTime)     
                    From ProdRoute as pr
                    Inner Join ProdRouteTran as prt on pr.ProdId = prt.ProdID and pr.OprNum = prt.MaxOpCompleted
                    Group By pr.ProdId, pr.OprNum
                ) as r
                left join ProdRoute as p on p.ProdId = r.ProdId and p.OprNum > r.OprNum
                Group By r.ProdId, r.OprNum, r.h
            )
            Select * From data
            

            【讨论】:

              【解决方案6】:

              我不完全确定我是否理解您想要做的事情,但这是否是等价的?

              SELECT
                 t.ProdId,
                 CASE WHEN r.OprNum IS NULL THEN t.MaxOpCompleted ELSE r.OprNum END AS OprNum
              FROM
                 ProdRouteTran t
                 LEFT JOIN
                    ProdRoute r
                 ON
                    r.ProdId = t.ProdId AND r.SetupTime + r.ProcessTime > 0 AND
                    r.OprNum > t.MaxOpCompleted AND NOT EXISTS(
                       SELECT * FROM ProdRoute p WHERE p.ProdId = t.ProdId AND
                          p.OprNum > t.MaxOpCompleted AND p.OprNum < r.OprNum)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-11-04
                • 2019-05-09
                • 1970-01-01
                • 2021-09-09
                • 1970-01-01
                • 1970-01-01
                • 2012-09-30
                • 1970-01-01
                相关资源
                最近更新 更多