这篇文章是继续发布另一篇帖子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
答案 0 :(得分:8)
基于新数据和对问答的最后评论,这里有更新的查询和小提琴: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
以下查询更改的说明:
对查询进行的唯一更改是使用以下语法处理NULL
的{{1}}值
weighted_value
有问题的部分是内部查询,当没有group by子句运行时,会显示在用户添加的边界情况下发生的情况。
(请参阅此处的小提琴:http://sqlfiddle.com/#!6/87e2f/3)
如果没有空值处理,我们有一个ISNULL(LEAD(a.oprnum,1) OVER(Partition by a.prodID ORDER by a.oprnum asc),a.oprnum)
,NULL
子句后导致下面的结构
(请参阅此处的小提琴:http://sqlfiddle.com/#!6/87e2f/5)
正如您所看到的那样,将group by
的LEAD值归为prodid : 12M0003381, oprnum:70
而不是NULL
(因为分组70
和70
应该给{{ 1}})。
如果在分组查询/表格上计算NULL
,这是合理的,这实际上就是这里发生的事情。
在这种情况下,70
函数不会返回最后一行分区的任何数据。这是边界情况,必须使用LEAD
正确处理。
我认为最后一行的LEAD
ISNULL
值应更正为当前行的LEAD
值。
以下旧答案:
所以我尝试了,我发布了小提琴链接 http://sqlfiddle.com/#!6/e965c/1
oprnum
答案 1 :(得分:6)
这不是我写过的最漂亮的东西,但它有效。我还用另外的数据对另一个小提琴进行了测试。
修改以满足新要求。
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]
答案 2 :(得分:6)
我不确定我理解你的问题,但这是我的尝试:
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
答案 3 :(得分:6)
试试这个 -
-- 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
答案 4 :(得分:6)
我使用此SQL Fiddle获得了正确的结果。
但我不确定我完全理解nothing >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
答案 5 :(得分:5)
我不完全确定我是否明白你想要做什么,但这可能是等同的吗?
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)