2015-08-07 11 views
10

Questo post è in continuatation di un problema di un altro post sql select min or max based on conditionSQL SELECT min o max in base alla condizione parte 2

Sto cercando di ottenere una riga basata su varie condizioni.

Scenario 1- ottenere più alto riga se non esistono ore contro di essa che ha (+ setupprocesstime> 0).

Scenario 2 - se ci sono ore (come in questo esempio) mostra l'operazione successiva (oprnum) dopo questo numero. (che sarebbe 60 in prodroute).

La query deve funzionare all'interno di un CTE poiché fa parte di una query più ampia.

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) 
; 

risultato atteso:

ProdId OprNum 
12M0004893 60 

ProdId OprNum 
12M0003571 70 

risposta

8

Sulla base di nuovi dati e ultimo commento sulla risposta per Richiedente, ecco la query aggiornato e violino: http://sqlfiddle.com/#!6/87e2f/2

hey ho trovato un esempio che non funziona ... orderID '12M0003381' ... ho aggiunto dati al tuo violino. Mi aspetto di vedere l'operazione 70 come che è l'ultima operazione con un tempo di installazione o di processo ... grazie!

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 

Spiegazione per qui di seguito le modifiche di query:

L'unica modifica apportata alla domanda è stato quello di gestire il valore NULL per weighted_value utilizzando la seguente sintassi

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

La parte problematica era la query interna che quando viene eseguita senza la clausola group by mostra cosa è successo in un caso limite come aggiunto dall'utente.

enter image description here

(Vedi violino per questo qui: http://sqlfiddle.com/#!6/87e2f/3)

Senza movimentazione nulla, abbiamo avuto un NULL che, dopo group by clausola ha provocato una struttura come di seguito enter image description here

(Cfr violino per questo qui: http://sqlfiddle.com/#!6/87e2f/5)

Come si può vedere sul raggruppamento del valore LEAD per prodid : 12M0003381, oprnum:70 risultante come NULL anziché 70 (poiché il raggruppamento 70 e NULL dovrebbe fornire 70).

Questo è giustificato se LEAD viene calcolato su query/tabella raggruppate, che in realtà è ciò che sta accadendo qui.

In tal caso, la funzione LEAD non restituirà alcun dato per l'ultima riga di partizione.Questo è il caso limite e deve essere gestito correttamente con ISNULL.

Ho assunto che il valore LEADoprnum dell'ultima riga debba essere corretto come valore oprnum della riga corrente.

Vecchio risposta qui sotto:

Così ho provato e mi metto il link violino 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 
6

Questa non è la cosa più bella che abbia mai scritto, ma lavori. L'ho anche testato contro l'altro violino con dati aggiuntivi.

Modificato per soddisfare i nuovi requisiti.

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] 
5

Non sono del tutto sicuro se ho capito cosa stai cercando di fare, ma potrebbe essere che questo è l'equivalente?

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) 
6

Io non sono davvero sicuro di aver capito la tua domanda, ma qui è il mio tentativo:

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 
5

Prova questa -

-- 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 
6

ottengo il risultato corretto con questo SQL Fiddle.

Tuttavia, non sono sicuro di aver compreso completamente il caso nothing >0. Un po 'più di dati con tutti i casi potrebbe essere utile.

; 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