简体   繁体   中英

Oracle SQL Query to get the RAG

RAG    PCT
------ ---
GREEN  100
AMBER   50
ORANGE  20
RED      0

I need an oracle query to result like (Suggest to use Inner Join or Outer Join)

if the given PCT >100 then Green
if the given PCT >=50 and PCT < 100 then AMBER
if the given PCT >=20 and PCT < 0 then ORANGE
else RED

You can implement the logic using CASE , like :

SELECT pct, CASE 
    WHEN pct >= 100 THEN 'GREEN'
    WHEN pct >= 50 THEN 'AMBER'
    WHEN pct >= 20 then 'ORANGE'
    ELSE 'RED'
END
FROM mytable

CASE stops on the first matching condition (hence no need to write WHEN pct >= 50 AND pct < 100 for example, since pct >= 100 is already caught by the previous condition.


If you are using a separate table to store the lower bound of each interval (like myranges ), as shown in your example, and you are looking to JOIN it with a table that cotains actual data (like mydata ), then it is a little more tricky : you would need to ensure that you are joining with the relevant range record :

SELECT d.*, r.*
FROM mydata d
INNER JOIN myranges r 
    ON d.value >= r.pct 
    AND (
        LEAD (r.pct) OVER (ORDER BY pct) IS NULL
        OR d.value < LEAD (r.pct) OVER (ORDER BY pct)
    )

What you're asking for doesn't entirely make sense - you've said "Use a join" but have provided nothing to join to , but never mind. The following strictly implements your spec:

WITH cteData AS (SELECT 'GREEN' AS RAG, 100 AS PCT FROM DUAL UNION ALL
                 SELECT 'AMBER', 50 FROM DUAL UNION ALL
                 SELECT 'ORANGE', 20 FROM DUAL UNION ALL
                 SELECT 'RED', 0 FROM DUAL)
SELECT RAG, PCT, CASE
                   WHEN PCT > 100 THEN 'GREEN'
                   WHEN PCT >= 50 AND PCT < 100 THEN 'AMBER'
                   WHEN PCT >= 20 AND PCT < 0 THEN 'ORANGE'
                   ELSE 'RED'
                 END AS COLOR
  FROM cteData;

When executed, the above produces:

RAG     PCT COLOR
GREEN   100 RED
AMBER   50  AMBER
ORANGE  20  RED
RED     0   RED

And may Codd have mercy upon your soul.

If I understand you correctly, I think this might be something like what you're after:

WITH rag_data AS (SELECT 'GREEN' AS rag, 100 AS PCT FROM DUAL UNION ALL
                  SELECT 'AMBER' AS rag, 50 AS PCT FROM DUAL UNION ALL
                  SELECT 'ORANGE' AS rag, 20 AS PCT FROM DUAL UNION ALL
                  SELECT 'RED' AS rag, 0 AS PCT FROM DUAL),
  sample_data AS (SELECT -1 NUM FROM dual UNION ALL
                  SELECT 0 NUM FROM dual UNION ALL
                  SELECT 1 NUM FROM dual UNION ALL
                  SELECT 19 NUM FROM dual UNION ALL
                  SELECT 20 NUM FROM dual UNION ALL
                  SELECT 21 NUM FROM dual UNION ALL
                  SELECT 49 NUM FROM dual UNION ALL
                  SELECT 50 NUM FROM dual UNION ALL
                  SELECT 51 NUM FROM dual UNION ALL
                  SELECT 99 NUM FROM dual UNION ALL
                  SELECT 100 NUM FROM dual UNION ALL
                  SELECT 101 NUM FROM dual)
SELECT NUM,
       rag,
       pct,
       rn
FROM   (SELECT sd.num,
               rd.rag,
               rd.pct,
               row_number() OVER (PARTITION BY sd.num ORDER BY rd.pct DESC) rn
        FROM   sample_data sd
               INNER JOIN rag_data rd ON sd.num >= rd.pct)
WHERE  rn = 1;

       NUM RAG           PCT         RN
---------- ------ ---------- ----------
         0 RED             0          1
         1 RED             0          1
        19 RED             0          1
        20 ORANGE         20          1
        21 ORANGE         20          1
        49 ORANGE         20          1
        50 AMBER          50          1
        51 AMBER          50          1
        99 AMBER          50          1
       100 GREEN         100          1
       101 GREEN         100          1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM