convert column to row in postgresql database - sql

My current query is:
select rulename,status, count(*)
from triggered_rule_info
group by status, rulename
And the result is:
rulename status count
eorule1 ack 1
eorule1 open 1
eorule1 close 7
eorule2 open 1
eorule2 ack 1
But I want the result to be:
rulename ack open close
eorule1 1 1 7
eorule2 1 1
How can I achieve this? My postgresql version is 9.4.

For that you can use the filter clause:
select rulename
count(*) filter (where status = 'ack') as ack,
count(*) filter (where status = 'open') as open,
count(*) filter (where status = 'close') as closed
from triggered_rule_info
group by rulename
order by rulename;

You can make use of CASE - WHEN and GROUP BY clauses to get the desired result. You may require to add more CASE statements if status has more other values.
Example:
SELECT rulename
, SUM( CASE status WHEN 'ack' THEN 1 ELSE 0 END ) AS "ack"
, SUM( CASE status WHEN 'open' THEN 1 ELSE 0 END ) AS "open"
, SUM( CASE status WHEN 'close' THEN 1 ELSE 0 END ) AS "close"
FROM triggered_rule_info
GROUP BY rulename
ORDER BY rulename

Related

Getting Count on 2 columns on SQL

I am trying to get a count on approved orders in a separate column.
Initial Table looks like this,
User name
Status
Count
User 1
Approved
1
Rejected
2
User 2
Approved
5
User 3
Approved
1
User 4
Approved
2
Rejected
5
But I want to get another column as a Approved Count,
User name
Status
Count
Approved Count
User 1
Approved
1
1
Rejected
2
User 2
Approved
5
5
User 3
Approved
1
1
User 4
Approved
2
2
Rejected
5
What is the best way of doing this?
You probably want to do something like this:
Select Count(User_Id) FROM table WHERE Status = 'Approved'
You could also try adding GROUP BY User_Id at the end
Try this one. I used same column names as you mentioned, but not recommended
Your impotent part is this one:
case when Status = 'Approved' then count else 0 end
Example
select *, case when Status = 'Approved' then count else 0 end Approved_count from table_X
where row_num = 1;
Full sample code
select *, case when Status = 'Approved' then count else 0 end Approved_count from (
select ROW_NUMBER() OVER (partition by user_name, Status ORDER BY user_name) row_num,
user_name, Status, count(Status) over (partition by user_name, Status) count
from [Count_test] )
A where row_num = 1;
You could try something using a case statement.
SELECT
Username,
Status,
Count,
CASE
WHEN Status = 'Approved'
THEN Count
ELSE ''
END AS approved_count
FROM
table1
db fiddle

sql case statement IN with group by

I have a 2 column table with the columns : "user_name" and "characteristic". Each user_name may appear multiple times with a different characteristic.
The values in characteristic are:
Online
Instore
Account
Email
I want to write a sql statement that goes like this - but obviously this isn't working:
SELECT user_name,
case
when characteristic in ("online","instore") then 1
else 0
END as purchase_yn,
case
when characteristic in ("online","instore") and
characteristic in ("email",'account') then 1
else 0
END as purchaser_with_account
FROM my_table
GROUP BY user_name;
Essentially the first is a flag where I check for the presence of either value for that user_name.
The Second field is that they meet this criteria AND that they meet the criteria for having either 'email' or 'account'
An example the structure of your data would help better understand what you are trying to accomplish. But I think I get what you are trying to do.
You have to use an aggregate function in order to use a group by.
Something like SUM or AVG.
But you need first to build a pivot of your data and then you could use that pivot to check for your criterias:
This would create a table pivot that shows for each record what criterias are met:
SELECT
user_name,
case when characteristic = "online" then 1 else 0 end as online_yn,
case when characteristic = "instore" then 1 else 0 end as instore_yn,
case when characteristic = "account" then 1 else 0 end as account_yn,
case when characteristic = "email" then 1 else 0 end as email_yn,
FROM my_table
Now what you might wanted to do is to create an averaged version of these entries grouped by user_name and use those averages to create the fields you wanted. For that you need to use the same statement created earlier as an inline table :
Select
user_name,
case when avg(online_yn + instore_yn) >= 1 then 1 else 0 end as purchase_yn,
case when avg(online_yn + instore_yn) >= 1 and avg(email_yn + account_yn) >= 1 then 1 else 0 end as purchaser_with_account
From
(SELECT
user_name,
case when characteristic = "online" then 1 else 0 end as online_yn,
case when characteristic = "instore" then 1 else 0 end as instore_yn,
case when characteristic = "account" then 1 else 0 end as account_yn,
case when characteristic = "email" then 1 else 0 end as email_yn,
FROM my_table) avg_table
group by
user_name;
This should help.
It may not be efficient in terms of performance but you'll get what you want.
You just have to enclose the CASE expressions in COUNT aggregates:
SELECT user_name,
COUNT(case when characteristic in ("online","instore") then 1 END) as purchase_yn,
COUNT(case when characteristic in ("email",'account') then 1 END) as user_with_account
FROM my_table
GROUP BY user_name
If purchase_yn > 0 then you first flag is set. If purchase_yn > 0 and user_with_account > 0 then you second flag is set as well.
Note: You have to remove ELSE 0 from the CASE expressions because COUNT takes into account all not null values.
You haven't mentioned a specific RDBMS, but if SUM(DISTINCT ...) is available the following is quite nice:
SELECT
username,
SUM(DISTINCT
CASE
WHEN characteristic in ('online','instore') THEN 1
ELSE 0
END) AS purchase_yn,
CASE WHEN (
SUM(DISTINCT
CASE
WHEN characteristic in ('online','instore') THEN 1
WHEN characteristic in ('email','account') THEN 2
ELSE 0 END
)
) = 3 THEN 1 ELSE 0 END as purchaser_with_account
FROM
my_table
GROUP BY
username
If I correctly understand, if user have 'online' or 'instore', then for this user you want 1 as purchase_yn column, and if user also have 'email' or 'account', then 1 as purchaser_with_account column.
If this is correct, then one way is:
with your_table(user_name, characteristic) as(
select 1, 'online' union all
select 1, 'instore' union all
select 1, 'account' union all
select 1, 'email' union all
select 2, 'account' union all
select 2, 'email' union all
select 3, 'online'
)
-- below is actual query:
select your_table.user_name, coalesce(max(t1.purchase_yn), 0) as purchase_yn, coalesce(max(t2.purchaser_with_account), 0) as purchaser_with_account
from your_table
left join (SELECT user_name, 1 as purchase_yn from your_table where characteristic in('online','instore') ) t1
on your_table.user_name = t1.user_name
left join (SELECT user_name, 1 as purchaser_with_account from your_table where characteristic in('email', 'account') ) t2
on t1.user_name = t2.user_name
group by your_table.user_name

How to group and get count of rows based on value of one column in sql server

I have a table of requests with columns RequestType,status .Status column values can be in-progress,complated etc.
I would like to get the list like
RequestType In-Progress Completed Total
Type1 10 5 15
Type2 10 10 20
I tried with group by using the 2 columns( RequestType,status) ,but it does not give me the exact result.
Please help me with the sql query.
Thanks in advance
Subin
One way to do it is using conditional aggrigation:
SELECT RequestType,
SUM(CASE WHEN Status = 'In-Progress' THEN 1 ELSE 0 END) As 'In-Progress',
SUM(CASE WHEN Status = 'Completed' THEN 1 ELSE 0 END) As 'Completed',
COUNT(Status) As 'Total'
FROM TableName
WHERE Status IN('In-Progress', 'Completed')
GROUP BY RequestType
Use PIVOT
select *, [In-Progress]+[Completed] total
from TableName
pivot ( count(status) for status in ([In-Progress], [Completed])) as p

SQL Server : do not Select all if true

I have these columns
Id Status
----------
1 pass
1 fail
2 pass
3 pass
How do I select all that only have a status of pass but if the Id has at least one fail it will not be selected as well.
If same id can have multiple passes
SELECT id
from table
WHERE status = 'pass'
and id NOT IN (SELECT id FROM table WHERE status = 'fail')
You need to use GROUP BY & HAVING clause
SELECT Id
FROM yourtable
GROUP BY Id
HAVING Sum(case when status ='pass' then 1 else 0 end) = count(status)
HAVING clause can be changed to
HAVING Count(case when status ='pass' then 1 end) = count(status)
I just hate chatty case statement, so
SELECT Id
FROM table1
GROUP BY Id
HAVING COUNT(DISTINCT [Status]) = 1 AND MIN([Status]) = 'pass'
or
SELECT Id
FROM table1
GROUP BY Id
HAVING COUNT(NULLIF([Status], 'fail')) = 1 AND COUNT(NULLIF([Status], 'pass')) = 0
The second query only works when status has two values 'pass' and 'fail'.

Counting groupwise category in SQL

I want to find a category wise count in sql server with multiple criteria
Below is the table
I want to find groupwise, checklistcode wise status count
for instance group CLT having total count for Open status and Closed status
so output should look like this
CLT | Clinker transport | CL07M1 | Mechanical Requirments | 4 | 1
I have tried query which is as follows,
select distinct pd.GroupCode,
pd.GroupName,
pd.CheckListCode,
pd.CheckListName,
OpenTotal =
CASE WHEN pd.Status = 'Open' THEN COUNT(pd.Status)
END,
ClosedTotal =
CASE WHEN pd.Status = 'Closed' THEN COUNT(pd.Status)
END
from PunchListDetails pd
group by pd.GroupCode,
pd.GroupName,
pd.CheckListCode,
pd.CheckListName,
pd.Status;
But results is not according to my needs. This above query is showing following result
This is showing in two different lines but i want it in aggregated form as explained above.
Your approach is correct, but you are (also) grouping by the status, so you'll get a different row for each status - hence you get one row that counts the open statuses and one that counts the closed ones.
Just remove pd.Status from the end of the group by clause and you should be fine:
select distinct pd.GroupCode,pd.GroupName,pd.CheckListCode,pd.CheckListName,
OpenTotal =
CASE WHEN pd.Status = 'Open' THEN COUNT(pd.Status)
END,
ClosedTotal =
CASE WHEN pd.Status = 'Closed' THEN COUNT(pd.Status)
END
from PunchListDetails pd
group by pd.GroupCode,pd.GroupName,pd.CheckListCode,pd.CheckListName
You can try this:
SELECT GroupCode
,GroupName
,CheckListCode
,CheckListName,
,SUM(CASE WHEN Status = 'Open' THEN 1 ELSE 0 END) as OpenTotal
,SUM(CASE WHEN Status = 'Closed' THEN 1 ELSE 0 END) as ClosedTotal
FROM PunchListDetails
GROUP BY GroupCode,GroupName,CheckListCode,CheckListName