Oracle
 sql >> Database >  >> RDS >> Oracle

Restituisce il valore zero quando non esistono dati di riga

Prima di tutto, riscrivi la tua domanda. Usa viste o espressioni di tabella comuni per evitare di ripeterti tre volte per il tuo SELECT , GROUP BY , ORDER BY clausole. La tua richiesta diventa:

WITH data AS (
    SELECT(CASE WHEN time_dtm > SYSDATE -1 THEN '0-1 day'
                WHEN time_dtm > SYSDATE -2 AND 
                     time_dtm < SYSDATE -1 THEN '1-2 days'
                WHEN time_dtm > SYSDATE -3 AND 
                     time_dtm < SYSDATE -2 THEN '2-3 days'
                WHEN time_dtm > SYSDATE -4 AND 
                     time_dtm < SYSDATE -3 THEN '3-4 days'
                WHEN time_dtm > SYSDATE -5 AND 
                     time_dtm < SYSDATE -4 THEN 'Closed'
           END) AS Age 
    FROM table_1 
    WHERE id IN (1,2,3)
)
SELECT Age, COUNT(*)
FROM data
GROUP BY Age
ORDER BY Age

Quindi, per essere sicuro che tutti i gruppi desiderati siano disponibili nel risultato, hai molte opzioni.

Potresti usare UNION ALL :

WITH data AS (
    SELECT(CASE WHEN time_dtm > SYSDATE -1 THEN '0-1 day'
                WHEN time_dtm > SYSDATE -2 AND 
                     time_dtm < SYSDATE -1 THEN '1-2 days'
                WHEN time_dtm > SYSDATE -3 AND 
                     time_dtm < SYSDATE -2 THEN '2-3 days'
                WHEN time_dtm > SYSDATE -4 AND 
                     time_dtm < SYSDATE -3 THEN '3-4 days'
                WHEN time_dtm > SYSDATE -5 AND 
                     time_dtm < SYSDATE -4 THEN 'Closed'
           END) AS Age 
    FROM table_1 
    WHERE id IN (1,2,3)

    -- The below will add one record for every desired Age group
    UNION ALL
    SELECT '0-1 day'  FROM DUAL UNION ALL
    SELECT '1-2 days' FROM DUAL UNION ALL
    SELECT '2-3 days' FROM DUAL UNION ALL
    SELECT '3-4 days' FROM DUAL UNION ALL
    SELECT 'Closed'   FROM DUAL
)
SELECT Age, COUNT(*) - 1 -- Subtract the extra record again
FROM data
GROUP BY Age
ORDER BY Age

Una soluzione completamente diversa comporterebbe LEFT OUTER JOINs :

-- Groups is a dynamic table that contains the date ranges and their "Age" label
WITH groups AS (
    SELECT SYSDATE -1 lower, SYSDATE upper, '0-1 day'  Age FROM DUAL UNION ALL
    SELECT SYSDATE -2      , SYSDATE -1   , '1-2 days'     FROM DUAL UNION ALL
    SELECT SYSDATE -3      , SYSDATE -2   , '2-3 days'     FROM DUAL UNION ALL
    SELECT SYSDATE -4      , SYSDATE -3   , '3-4 days'     FROM DUAL UNION ALL
    SELECT SYSDATE -5      , SYSDATE -4   , 'Closed'       FROM DUAL
)
SELECT g.Age, NVL(SUM(t.counter), 0)
FROM groups g

-- LEFT OUTER JOINing "table_1" to "groups" will ensure that every group
-- appears at least once in the result
LEFT OUTER JOIN (
  SELECT 1 counter, t.* FROM table_1 t WHERE t.id IN (1,2,3)
) t
ON  t.time_dtm >= g.lower
AND t.time_dtm <  g.upper
GROUP BY g.Age
ORDER BY g.Age

Nel secondo esempio, potresti anche fare a meno di un CTE e utilizzare un SELECT annidato per i groups tavolo. È facile vedere come il secondo esempio sia più semplice da evolvere in futuro, se le tue esigenze dovessero cambiare.