简体   繁体   中英

Oracle SQL create a virtual column, do a max and then count and displaying records

Sorry if the title is a bit misleading but I don't know how else to put it. Anyways back to problem at hand. I have 2 tables WSM(contains warehouse id, name and risk associated with it) and SUTSM_REP(store and warehouse relation). Below are values what they hold: WSM table

SUTSM_REP

Every warehouse has a risk associated with it(4 risks categories - Low, Medium, High & Critical) and a store gets stuff from multiple warehouses. If a store gets stuff from 3 warehouses(say for eg w1(medium risk), w2(high), w3(low)) then the risk associated with the store is 'High'. Similarly if a store gets stuff from 2 warehouses - 1 with medium and another with low risk then the store gets 'Medium' risk. I hope I am clear with this point. I was asked to bring up the count of Stores with each risk. So what I did was I created another table with risk and risk id. I assigned 1 to Low, 2 to medium, 3 to high and 4 to critical. Then I joined the 3 tables along with max of risk id and then did a count of that. Below is my query :

select RID, count(sp_id)
from
  (select a.sp_id, max(c.r_id) AS RID
   from SUTSM_REP a,
        WSM b,
        wsm_rid c
   where a.sm_id = b.sm_id and b.smr = c.smr
   group by a.sp_id) t
group by RID;

And the result is : my query result

But boss doesn't want a 3rd table to be created and he wants Risk names (Low, Medium, High, Critical) instead of Risk IDs. So I modified the query to :

with t as (
  select sm_id, sm_name, smr, DECODE(smr, 'Low', 1,
                                    'Medium', 2,
                                    'High', 3,
                                    'Critical', 4,
                                    0) RISK_ID 
   from wsm )
select rid, count(sp_id) from 
    ( select sp_id, max(risk_id) rid 
      from (select a.sp_id, b.sm_id, b.risk_id 
            from SUTSM_REP a, t b 
            where a.sm_id=b.sm_id) 
       group by sp_id ) 
group by rid;

I created a temp table using the wsm and added the risk id to the risk category/level. And then used the same logic as earlier. Output of this query is :

We use Oracle SQL. Can anyone please help me or point me in the direction of how to get the names of Risk Categories/Levels? I am at my wits end here. Thanks in advance to any posters for their help.

Would it help to decode the RISK_ID back into the respective categories? Sample below ..

with t as (
  select sm_id, sm_name, smr, DECODE(smr, 'Low', 1,
                                    'Medium', 2,
                                    'High', 3,
                                    'Critical', 4,
                                    0) RISK_ID 
   from wsm )
select rid, 
DECODE(rid, 1, 'Low',
            2, 'Medium',
            3, 'High',
            4, 'Critical') smr,
count(sp_id) from 
    ( select sp_id, max(risk_id) rid 
      from (select a.sp_id, b.sm_id, b.risk_id 
            from SUTSM_REP a, t b 
            where a.sm_id=b.sm_id) 
       group by sp_id ) 
group by rid;



Alternatively, you may use the rank function

select smr, count(distinct sp_id) from (
select s.sp_id, w.smr,
rank () over (partition by s.sp_id order by 
DECODE(smr, 'Low', 1,
            'Medium', 2,
            'High', 3,
            'Critical', 4,
             0) desc
) rnk
from wsm w
join sutsm_rep s on w.sm_id = s.sm_id
) where rnk = 1
group by smr
;



If this doesn't work, please share your expected output. Also, please consider using db fiddle. I've added a sample here .

It would be best to have a risk table holding the risk names and their relevance. If you are not allowed to create such table, create them as an ad-hoc view with WITH on-the-fly.

The next step is getting the highest risk per store, which can be got with a join to above risk table and KEEP LAST .

The last step is counting stores per risk.

with risks as
(
  select 'Low' as smr, 1 as relevance from dual
  union all
  select 'Medium' as smr, 2 as relevance from dual
  union all
  select 'High' as smr, 3 as relevance from dual
  union all
  select 'Critical' as smr, 4 as relevance from dual
)
, store_risks as
(
  select
    sw.sp_id,
    max(w.smr) keep (dense_rank last order by r.relevance) as risk,
    max(r.relevance) as risk_sortkey
  from sutsm_rep sw -- the store/warehouse bridge
  join wsm w on w.sm_id = sw.sm_id -- the warehouses
  join risks r on r.smr = w.smr -- the risks
  group by sw.sp_id
)
select risk, count(*)
from store_risks
group by risk
order by max(risk_sortkey);

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