简体   繁体   中英

SELECTING aggregate data using CASE statement issue

I'm trying to create a query to obtain zone data in preparation to moving the column to another table. How our DB is set up is that we have assets and cables. One asset can have many cables but a cable cannot have multiple assets. We're currently trying to move the Zone field from the Cable table (ex. Below) to the Asset table.

A_ID    C_ID       Zone        
--------------------------
1       1          Green
1       2          Green   
1       3          Yellow
2       4          Green
2       5          Red
3       6          Yellow
3       7          Yellow
3       8          Yellow
3       9          Red

The way I want it to be set up for the Asset table is if the Asset contains multiple cables with different zones, if one of the zones is Yellow it defaults to Yellow (ex. 3 green cables, 1 yellow cable - Asset_ID has Yellow zone). Next if it doesn't have any Yellows but has at least 1 red, it defaults to Red (ex. 2 green cables, 3 red cables - Asset_ID has Red Zone). Only if it just has Green zones then it defaults to Green.

Using the sample table above these are the results I would expect.

Expected Results    

A_ID   Zone
-------------
1      Yellow
2      Red
3      Yellow

I'm trying to use CASE statements but I'm having difficulty formulating the query to group the results correctly.

Any help would be greatly appreciated, thank you in advance.

No case or if statement needed. Think in sets. You need to assign a priority join to the priority and select the one with the highest priority first. Like this

WITH Priority AS
(
   SELECT * FROM (
   VALUES
     ('Yellow', 1),
     ('Red', 2),
     ('Green', 3)
   ) AS P(Zone,P)
)
SELECT A_ID, Zone
FROM (     
  SELECT A_ID, Zone
         ROW_NUMBER() OVER (PARTITION BY A_ID ORDER BY P.P ASC) AS RN
  FROM AssetTable A
  LEFT JOIN Priority P ON A.Zone = P.Zone
) SUB
WHERE RN = 1 

Not sure if my syntax is right for VALUES in CTE for Oracle. if that gives an error replace with this:

WITH Priority AS
(
   SELECT 'Yellow' AS Zone, 1 AS P
     UNION ALL
   SELECT 'Red' AS Zone, 2 AS P
     UNION ALL
   SELECT 'Green' AS Zone, 3 AS P
)

One way to do it using conditional aggregation and a case expression.

select a_id
,case when yellow_count >=1 then 'Yellow'
      when yellow_count = 0 and red_count >=1 then 'Red'
      when yellow_count = 0 and red_count = 0 and green_count >=1 then 'Green'
 end zone
from (select a_id,
      count(case when zone = 'Yellow' then 1 end) yellow_count,
      count(case when zone = 'Red' then 1 end) red_count
      count(case when zone = 'Green' then 1 end) green_count
      from cable_table
      group by a_id) t

Why just don't do a simple:

SELECT A_ID, MAX( Zone )
FROM table
GROUP BY A_ID

if some A_ID has Yellow then max( Zone ) returns Yellow
if some A_ID hasn't Yellow , but has Red then max( Zone ) returns Red <br> otherwise (no Yellow nor Red ) max( Zone ) returns Green`

and example:

with data as (
select 1  a_id,   1 c_id ,         'Green' zone from dual union all
select 1   ,    2  ,        'Green'  from dual union all
select 1 ,      3,          'Yellow' from dual union all
select 2 ,      4 ,         'Green' from dual union all
select 2 ,      5 ,         'Red' from dual union all
select 3  ,     6  ,       'Yellow' from dual union all
select 3   ,    7   ,       'Yellow' from dual union all
select 3   ,    8        ,  'Yellow' from dual union all
select 3   ,    9   ,       'Red' from dual 
)
select a_id, max( zone )
from data
group by a_id


      A_ID MAX(ZO
---------- ------
         1 Yellow
         2 Red   
         3 Yellow

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