Reputation: 43
I have a dataset that I want to aggregate based on a string column. Dataset is basically:
system status
-------------------
PRE1-SYS1 SUCCESS
PRE1-SYS2 SUCCESS
PRE2-SYS1 RUNNING
PRE2-SYS2 SUCCESS
PRE3-SYS1 SUCCESS
PRE3-SYS2 <blank>
Basically, I want this to become:
system status
-------------------
PRE1 SUCCESS
PRE2 RUNNING
PRE3 RUNNING
I have the sql needed to trim down the system values to PRE1, and PRE2, but I'm not sure how to aggregate the string function so that a system is:
I've looked at LISTAGG but I don't think it applies.
Upvotes: 1
Views: 66
Reputation: 231781
Another alternative. Practically, this ends up being very similar to @trincot's solution, I'm just separating the logic for getting the counts from the logic that interprets those counts. If your logic gets more complicated in the future, this may be a bit more flexible.
with
inputs ( system, status ) as (
select 'PRE1-SYS1', 'SUCCESS' from dual union all
select 'PRE1-SYS2', 'SUCCESS' from dual union all
select 'PRE2-SYS1', 'RUNNING' from dual union all
select 'PRE2-SYS2', 'SUCCESS' from dual union all
select 'PRE3-SYS1', 'SUCCESS' from dual union all
select 'PRE3-SYS2', '' from dual
),
/* The cnts CTE counts how many rows relate to a SYSTEM,
how many of those are SUCCESS, and how many are NULL.
*/
cnts( system, num_rows, num_success, num_null ) as (
select substr(system,1,instr(system, '-')-1) system,
count(*),
sum(case when status = 'SUCCESS' then 1 else 0 end),
sum(case when status is null then 1 else 0 end)
from inputs
group by substr(system,1,instr(system, '-')-1)
)
/* Using the counts from the CTE, we can implement whatever logic we
want
*/
select system,
(case when num_rows = num_success then 'SUCCESS'
when num_rows = num_null then 'PENDING'
else 'RUNNING'
end) status
from cnts
Upvotes: 0
Reputation: 1290
I would approach it by ranking the responses. For example set a value to the most desired to the least desired results:
SUCCESS = 1
RUNNING = 2
<blank> = 3
PENDING = 3
Then select a min based on that.
select xval = case status when 'Success' then 1
when 'Running' then 2
when 'Pending' then 3
else 3
end
Use a nested sub select on the value you get here so you only get one record per system. select System, Min(Xval)
then display the 1 as Success
the 2 as Running
and 3 as Pending
It is hard to do in text format, easier to do with numbers. The numbers you assign to the string are important because they determine when you have multiple values which single one you return in your final query.
Upvotes: 0
Reputation:
with
inputs ( system, status ) as (
select 'PRE1-SYS1', 'SUCCESS' from dual union all
select 'PRE1-SYS2', 'SUCCESS' from dual union all
select 'PRE2-SYS1', 'RUNNING' from dual union all
select 'PRE2-SYS2', 'SUCCESS' from dual union all
select 'PRE3-SYS1', 'SUCCESS' from dual union all
select 'PRE3-SYS2', '' from dual
),
prep ( system, flag ) as (
select substr(system, 1, instr(system, '-') - 1),
case status when 'SUCCESS' then 0
when 'RUNNING' then 1 else 2 end
from inputs
)
select system,
case when min(flag) = 2 then 'PENDING'
when max(flag) = 0 then 'SUCCESS'
else 'RUNNING' end as status
from prep
group by system
order by system;
Output:
SYSTEM STATUS
--------- -------
PRE1 SUCCESS
PRE2 RUNNING
PRE3 RUNNING
Upvotes: 2
Reputation: 350841
Here is an SQL query you could use:
select regexp_substr(system, '^[^-]*') as prefix,
case
when count(status) = 0 then 'PENDING'
when count(*) = count(case when status = 'SUCCESS' then 1 end) then 'SUCCESS'
else 'RUNNING'
end as status
from mytable
group by regexp_substr(system, '^[^-]*')
Upvotes: 2