How to save the switch cases results in different columns - sql

I have the following query currently:
SELECT name, id,
CASE
WHEN( status = 'Missing' AND severity = 'Optional' ) AND ( id=123 )
THEN COALESCE(count(patchid),0)
ELSE 0
END AS missingoptional,
CASE
WHEN( status = 'Missing' AND severity = 'Important' ) AND ( id=123 )
THEN COALESCE(count(patchid),0)
ELSE 0
END as missingimportant
FROM tablename
GROUP BY name, id, status, severity
ORDER BY id
Current result:
name id missingoptional missingimportant
abc 123 10 0
abc 123 0 20
Expected result:
name id missingoptional missingimportant
abc 123 10 20
Please let me know what changes do I have to do in the above query to get the expected output.

Perhaps this is what you want:
SELECT name, id,
SUM(CASE
WHEN( status = 'Missing' AND severity = 'Optional' ) AND ( id=123 )
THEN 1
ELSE 0
END) AS missingoptional,
SUM(CASE
WHEN( status = 'Missing' AND severity = 'Important' ) AND ( id=123 )
THEN 1
ELSE 0
END) as missingimportant
FROM tablename
GROUP BY name, id
ORDER BY id
I removed status and severity from the GROUP BY, and instead put SUM() in the select-list to do aggregation.

Use MAX() aggregate function
SELECT name, id,
MAX(CASE
WHEN( status = 'Missing' AND severity = 'Optional' ) AND ( id=123 )
THEN COALESCE(count(patchid),0)
ELSE 0
END) AS missingoptional,
MAX(CASE
WHEN( status = 'Missing' AND severity = 'Important' ) AND ( id=123 )
THEN COALESCE(count(patchid),0)
ELSE 0
END) as missingimportant
FROM tablename
GROUP BY name, id
ORDER BY id

Related

Select single value from same columns based on condition

I have below table and using oracle sql
table name : TestCaseStatus
TestName Status TimeStamp
ABC Passed 11.10AM (Same Date)
ABC Failed 11.00 AM
ABC Failed 10.50 AM
EFG Passed 11.00AM
123 Failed 11.10 AM
123 Passed 11.00 AM
Result
TestName Status
ABC Passed_On_ReRun
123 Failed
EFG Passed
Question : Need query to get it. I have Tried MAX but not working
You can do this with window functions:
select
TestName,
case
when Status = 'Passed' and failed_once = 1
then 'Passed_On_Rerun'
else Status
end Status
from (
select
t.*,
rank() over(partition by TestName order by Timestamp desc) rn,
max(case when Status = 'Failed' then 1 else 0 end) over(partition by TestName) failed_once
from TestCaseStatus t
) t
where rn = 1
Demo on DB Fiddle:
TESTNAME | STATUS
:------- | :--------------
123 | Failed
ABC | Passed_On_Rerun
EFG | Passed
Assuming these are the only three conditions, you can use conditional aggregation:
select testname,
(case when max(timestamp) = max(case when status = 'Failed' then timestamp end)
then 'Failed'
when max(timestamp) = max(case when status = 'Passed' then timestamp end) and
sum(case when status = 'Failed' then 1 else 0 end) > 0
then 'Passed_On_Rerun'
when max(timestamp) = max(case when status = 'Passed' then timestamp end)
then 'Passed'
else '???'
end)
from TestCaseStatus tcs
group by testname;
In Oracle, you can simplify this to:
select testname,
(case when max(status) keep (dense_rank first order by timestamp desc) = 'Passed' and
sum(case when status = 'Failed' then 1 else 0 end) > 0
then 'Passed_On_Rerun'
else max(status) keep (dense_rank first order by timestamp desc)
end)
from TestCaseStatus tcs
group by testname;
Here is a db<>fiddle.
The keep syntax is getting the last value for the status based on the timestamp.
You may achieve what you want with the following query :
SELECT T1.TestName, T1.Status
FROM TestCaseStatus T1
WHERE T1.TimeStamp =
(SELECT MAX(T2.TimeStamp) FROM TestCaseStatus T2 WHERE T2.TestName = T1.TestName)
However, there is an issue with your sample data :
123 Failed 11.00 AM
123 Passed 11.00 AM
Same test is failed and passed for the same timestamp ?!
Edit : In order to achieve the 'Passed_On_ReRun' need, we could imagine a solution like this :
SELECT T1.TestName, IF(T1.count > 0 AND T1.Status = 'Passed', 'Passed_On_ReRun', T1.Status)
FROM
(SELECT T2.TestName
, T2.Status
, SUM(T2.Status = 'Failed') AS count
, MAX(T2.TimeStamp) AS TimeStamp
FROM TestCaseStatus T2
GROUP BY T2.TestName) T1

Group by and replace

I have a table like that :
groupe subgroup id status
A a 1 up
A b 1 notdefined
A c 1 null
A a 2 up
A b 2 up
A c 2 up
A a 3 up
A b 3 up
A c 3 null
What I need is that for each combination (group-id) return a specified status
if for each (group,id) there is a status with notdefined return the global status as notdefined
if all status = up return global status = up
if there is up but there is a null return notspecified
so the result should be like that
Groupe id global_status
A 1 notdefined
A 2 up
A 3 notspecified
I've tried something on sqlfiddle
You can use aggregation and conditional logic:
select groupe, id,
(case when count(*) filter (where status = 'notdefined') > 0
then 'notdefined'
when count(*) filter (where status is null) > 0
then 'notspecified'
when max(status) = min(status) and min(status) = 'up'
then 'up'
else 'something else'
end) as global_status
from t
group by groupe, id;
Use boolean aggregates:
select
groupe,
id,
case
when bool_and(status = 'up') then 'up'
when bool_or(status = 'notdefined') then 'notdefined'
else 'notpecified'
end as status
from tab
group by 1, 2
order by 1, 2
SqlFiddle.

case statement for each row manipulations

Hi I have a table which has an ID and status.One ID can have multiple status but I have to pick status based on the conditions.
If ID 1 has Approved, Later,Modified I should Pick Approved and if the ID has only approved then Pick only Approved.But the case statement I got is not doing per ID.It is changing the overall data based on status.Please advise
select ID,
CASE
WHEN status = 'Approved'
AND status IN(
'Modified',
'Later'
) THEN 'Partial Modified'
WHEN status = 'Approved' THEN 'Approved'
when status IN('Modified','Edited') THEN 'Modified'
else status
END status group by ID,Status
This can be done with an ordering condition in row_number.
select top 1 with ties *
from tbl
order by row_number() over(partition by id order by case when status='Approved' then 1
when status='Modified' then 2
else 3 end)
I think you want an aggregation, so something like this:
(CASE WHEN SUM(CASE WHEN status = 'Approved' THEN 1 ELSE 0 END) > 0
THEN 'Approved'
WHEN SUM(CASE WHEN status = 'Modified' THEN 1 ELSE 0 END) > 0
THEN 'Modified'
ELSE MAX(status)
END)
Of course, you can also do this using window functions:
(CASE WHEN SUM(CASE WHEN status = 'Approved' THEN 1 ELSE 0 END) OVER (PARTITION BY id) > 0
THEN 'Approved'
WHEN SUM(CASE WHEN status = 'Modified' THEN 1 ELSE 0 END) OVER (PARTITION BY id) > 0
THEN 'Modified'
ELSE MAX(status) OVER (PARTITION BY id)
END)

Comparing values in two columns and returning values on conditional bases using sql hive

I have two columns, I want to get an output based on a comparative basis of both. My data is somewhat like:
Customer Id status
100 A
100 B
101 B
102 A
103 A
103 B
So a customer can have a status A or B or both, I have to segrerate them on customer id basis for a status. If status A and B then return happy, if only A, return Avg and if only B return Sad.
try the below query,
SELECT DISTINCT Customer_Id,
(CASE WHEN COUNT(*) OVER(PARTITION BY Customer_Id) > 1 THEN 'happy'
WHEN Tstatus = 'A' THEN 'Avg'
ELSE 'Sad'END) AS New_Status
FROM #table1
GROUP BY Customer_Id,Tstatus
if Customer Id and status is a unique combination then
STEP 1: use case to determine a or b
SELECT customer id
,CASE WHEN avg(case when [status] ='A' then 0 else 2 end)
FROM [Your Table]
group by[customer id]
and step 2 will be casing avg into result: like this
SELECT customer id
,CASE WHEN (avg(case when [status] ='A' then 0 else 2 end)) = 1 THEN 'happy' ELSE WHEN (avg(case when [status] ='A' then 0 else 2 end)) = 0 THEN 'Avg' ELSE 'Sad' END
FROM [Your Table]
group by[customer id]
I would do this simply as:
select customer_id,
(case when min(status) <> max(status) then 'happy'
when min(status) = 'A' then 'avg'
else 'sad'
end)
from t
where status in ('A', 'B')
group by customer_id

get the closest

How do I get output in the below format using sql?
I am able to do it with case sum, but I am not able to get unique user count in the same line.
id unique_users male_count female_count
101 3 1 2
201 1 0 1
.
.
select id,
count(distinct user) as unique_users,
sum(case when gender = 'M' then 1 else 0 end) as male_count,
sum(case when gender = 'F' then 1 else 0 end) as female_count
from your_table
group by id
Alternative counts distinct males and females.
SELECT
ID,
COUNT(DISTINCT "USER") AS unique_users,
COUNT(DISTINCT DECODE(gender,'M',"USER")) AS male_count,
COUNT(DISTINCT DECODE(gender,'F',"USER")) AS female_count
FROM your_table
GROUP BY ID
ORDER BY ID;
And the same but without the Oracle specific DECODE function.
SELECT
ID,
COUNT(DISTINCT "USER") AS unique_users,
COUNT(DISTINCT CASE gender WHEN 'M' THEN "USER" ELSE NULL END) AS male_count,
COUNT(DISTINCT CASE gender WHEN 'F' THEN "USER" ELSE NULL END) AS female_count
FROM your_table
WHERE ID = 101
GROUP BY ID
ORDER BY ID;
I've quoted "USER" as it has a specific meaning in Oracle.