How to use nested case and group together the result in SQL - sql

How to use nested case and grouped together the result.
Here is my Query:
SELECT COUNT(inc.inc_id) AS event_count,
CASE inc_data.event_type
WHEN 'c' then case inc_data.sub_event_type
when 's' then 'SR' else 'Project'
end
WHEN 'i' then 'incident'
WHEN 'p' then 'Problem'
WHEN 'd' then 'Decision'
WHEN 't' then 'Task'
end "event_sub_type"
FROM inc INNER JOIN inc_data ON inc.inc_id = inc_data.inc_id
GROUP BY inc_data.event_type, inc_data.sub_event_type
Returns:
+-------------+----------------+
| event_count | event_sub_type |
+-------------+----------------+
| 5 | Project |
| 10 | Decision |
| 15 | Incident |
| 20 | Problem |
| 25 | Task |
| 30 | SR |
+-------------+----------------+
Expected output:
+-------------+----------------+
| event_count | event_sub_type |
+-------------+----------------+
| 5 | Project |
| 25 | Others |
+-------------+----------------+
How can I modify the above query to get the expected output?

Could you try this?
SELECT COUNT(inc.inc_id) AS event_count,
(CASE WHEN (inc_data.event_type = 'c' AND inc_data.sub_event_type <> 's') THEN 'Project' ELSE 'Others' END ) "event_sub_type"
FROM inc INNER JOIN
inc_data ON inc.inc_id = inc_data.inc_id
GROUP BY (CASE WHEN (inc_data.event_type = 'c' AND inc_data.sub_event_type <> 's') THEN 'Project' ELSE 'Others' END )

How about
SELECT COUNT(inc.inc_id) AS event_count,
CASE inc_data.event_type
WHEN 'c' then case inc_data.sub_event_type
when 's' then 'Other' else 'Project'
end
ELSE 'Project'
END "event_sub_type"
FROM inc INNER JOIN inc_data ON inc.inc_id = inc_data.inc_id
GROUP BY inc_data.event_type, inc_data.sub_event_type

Based on your output, I'm assuming that you are using MySQL.
MySQL allows you to group by column numbers, so you can replace your GROUP BY clause with this:
GROUP BY 1, 2

Related

How to get column wise sum in SQL?

I have a complex query where I am getting the count of various categories in separate columns.
Here's the output of my query:
district | colA | colB | colC
------------------------------------
DistA | 1 | 1 | 3
DistB | 2 | 0 | 2
DistC | 2 | 1 | 0
DistD | 0 | 3 | 4
..
And here's my query:
select
q1."district",
coalesce(max(case q1."type" when 'colA' then q1."type_count" else 0 end), 0) as "colA",
coalesce(max(case q1."type" when 'colB' then q1."type_count" else 0 end), 0) as "colB",
coalesce(max(case q1."type" when 'colC' then q1."type_count" else 0 end), 0) as "colC"
from (
select
d."name" as "district",
t."name" as "type",
count(t.id) as "type_count"
from
main_entity as m
inner join type_entity as t on
m."type_id" = t.id
inner join district as d on
m."district_id" = d.id
where
m."delete_at" is null
group by
d."name",
t.id
) as q1
group by
q1."district"
I want to modify this query so that I can get the sum of each column in the last row, something like this:
district | colA | colB | colC
------------------------------------
DistA | 1 | 1 | 3
DistB | 2 | 0 | 2
DistC | 2 | 1 | 0
DistD | 0 | 3 | 4
..
Total | 5 | 5 | 9
I have tried using group by + rollup with the above query by just adding the following:
...
group by rollup (q1."district")
It adds a row at the bottom but the values are similar to the values of a row before it, and not the sum of all the rows before it, so basically something like this:
district | colA | colB | colC
------------------------------------
DistA | 1 | 1 | 3
..
DistD | 0 | 3 | 4
Total | 0 | 3 | 4
So, how can I get the column-wise some from my query?
Try this:
With temp as
( --your query from above
select
q1."district",
coalesce(max(case q1."type" when 'colA' then q1."type_count" else 0 end), 0) as "colA",
coalesce(max(case q1."type" when 'colB' then q1."type_count" else 0 end), 0) as "colB",
coalesce(max(case q1."type" when 'colC' then q1."type_count" else 0 end), 0) as "colC"
from (
select
d."name" as "district",
t."name" as "type",
count(t.id) as "type_count"
from
main_entity as m
inner join type_entity as t on
m."type_id" = t.id
inner join district as d on
m."district_id" = d.id
where
m."delete_at" is null
group by
d."name",
t.id
) as q1
group by
q1."district"
)
select t.* from temp t
UNION
select sum(t1.colA),sum(t1.colB),sum(t1.colC) from temp t1

How to filter out column duplicates when multiple selected (SQL Server)

I am trying to get all list names and a condition whether a specific item is contained in any of those lists.
Example data:
| item | name |
+------+------+
| 1 | A |
| 2 | A |
| 3 | B |
| 4 | C |
Current output:
| isFavorited | name |
+-------------+------+
| N | A |
| Y | A |
| N | B |
| N | C |
Expected output:
| isFavorited | name |
+-------------+------+
| Y | A |
| N | B |
| N | C |
Query:
declare #idItem nvarchar(50) = 'A'
select distinct
'isFavorited' = case when item = #idItem then 'Y' else 'N' end,
'nameList' = name
from
favorites
group by
name
How can I get a list of all distinct list names flagged for when an item is contained in that list?
One approach would be to use self join and check if we have matching name with different item numbers.
with cte as (
select 1 as Item, 'A' as Name union all
select 2 as Item, 'A' as Name union all
select 3 as Item, 'B' as Name union all
select 4 as Item, 'C' as Name)
select c.name, case when c1.name is not null then 'Y' Else 'N' End IsFavorited from cte c
left join cte c1 on c1.Name = c.name and c.Item != c1.Item
group by c.name , case when c1.name is not null then 'Y' Else 'N' End
Output:
If I am understanding the problem correct, then try this:
with cte1(name, cnt) as
(
select name, count(*) as cnt
from favorites
group by name
)
select name,
case when cnt = 1 then 'N' else 'Y' end as IsFavorited
from cte1
OR alternatively:
select distinct name,
case when name = 'A' then 'Y' else 'N' end IsFavorited
from favorites
You can filter duplicates of isFavorited by using the max() function.
declare #idItem nvarchar(50) = 'A'
select distinct
'isFavorited' = max(case when item = #idItem then 'Y' else 'N' end),
'nameList' = name
from
favorites
group by
nameList

how to sum 2 record when using left join in sql server?

I have a problem when I use left join and group by running this code:
select a.[fromAccCode]
,a.[CenterCode]
, CASE WHEN b.CFCUSTYP = 0 THEN 'm' ELSE 'n' END AS person
,sum(a.[value]) 'sumValue'
from [dbo].[tmp_dep_ex] a left join [dbo].[5_CBCIF] b
on a.[CFCIFNO]=b.[CFCIFNO]
group by a.[CenterCode]
,a.[fromAccCode]
,b.CFCUSTYP
order by
a.[CenterCode]
,a.[fromAccCode]
,b.CFCUSTYP
The result is:
Result is
fromAccCode | CenterCode | person | sumValue
201443 | 3/2/0160 | m | 1707632873
201443 | 3/2/0160 | n | 8723822181
201443 | 3/2/0160 | m | 173260000
How to change this result to:
fromAccCode | CenterCode | person | sumValue
201443 | 3/2/0160 | m | 1880892873
201443 | 3/2/0160 | n | 8723822181
Thanks for reading my question.
you need to add CASE WHEN b.CFCUSTYP = 0 THEN 'm' ELSE 'n' END in group by clause
select a.[fromAccCode]
,a.[CenterCode]
, CASE WHEN b.CFCUSTYP = 0 THEN 'm' ELSE 'n' END AS person
,sum(a.[value]) 'sumValue'
from [dbo].[tmp_dep_ex] a left join [dbo].[5_CBCIF] b
on a.[CFCIFNO]=b.[CFCIFNO]
group by a.[CenterCode]
,a.[fromAccCode]
,CASE WHEN b.CFCUSTYP = 0 THEN 'm' ELSE 'n' END
order by
a.[CenterCode]
,a.[fromAccCode]

SQL - Sum two columns group by ID

I would like to sum two columns "Immo"+"Conso" group by "ID" in order to create a new variable "Mixte". My new variable "Mixte" is as follow:
if one ID has (at least) 1 in "Immo" AND 1 in "Conso" then "Mixte" is yes, otherwise "Mixte" is no.
For exemple:
Ident | Immo | Conso | Mixte
---------------------------------
1 | 0 | 1 | yes
1 | 1 | 0 | yes
2 | 1 | 0 | no
3 | 0 | 1 | no
3 | 0 | 1 | no
3 | 0 | 1 | no
4 | 0 | 1 | yes
4 | 0 | 1 | yes
4 | 1 | 0 | yes
Thank you for helping me. Do not hesitate to ask me questions if I wasn't clear.
Use a correlated sub-select:
select t1.Ident, t1.Immo, t1.Conso,
case when (select max(Immo) + max(Conso) from tablename t2
where t2.Ident = t1.Ident) = 2 then 'yes'
else 'no'
end as Mixte
from tablename t1
Ident is a reserved word in ANSI SQL, so you may need to delimit it as "Ident".
select ident,result=(case when sum(Immo)>0 and sum(Conso)>0 then 'yes'
else 'no' end)
from tabname (NOLOCK)
group by id
It may not be the smoothiest way but I'll do this as:
WITH X AS
(
SELECT T.Ident, MAX(T.Immo) Immo, MAX(T.Conso) Conso FROM Table AS T
GROUP BY T.Ident
)
SELECT X.*
,CASE WHEN X.Immo > 0 AND X.Conso > 0 THEN 'YES'
ELSE 'NO'
END Mixte
FROM X
In SQL-Server you could try to use window functions, something like:
select Ident, Immo, Conso,
case when rn1 > 0 and rn2 > 0 then 'Yes' else 'No' end as Mixte
from (
select
max(Immo) over (partition by Ident) rn1,
max(Conso) over (partition by Ident) rn2,
*
from table_name
)x

Rewriting SQL query to get record id and customer number

Sample data
+-------------------+-------------+-----------------+---------------------+
| RECORD_ID | CUST_NO | IsAccntClosed | Code |
+-------------------+-------------+-----------------+---------------------+
|159045 | 2439123 | N | 13 |
+-------------------+-------------+-----------------+---------------------+
|159048 | 6376150 | Y | 13 |
+-------------------+-------------+-----------------+---------------------+
|159048 | 9513035 | N | 13 |
+-------------------+-------------+-----------------+---------------------+
|159049 | 2398524 | N | 12 |
+-------------------+-------------+-----------------+---------------------+
|159049 | 6349269 | Y | 12 |
+-------------------+-------------+-----------------+---------------------+
|159049 | 6350690 | Y | 12 |
+-------------------+-------------+-----------------+---------------------+
|159049 | 6372163 | Y | 12 |
+-------------------+-------------+-----------------+---------------------+
|159049 | 6393810 | Y | 12 |
+-------------------+-------------+-----------------+---------------------+
|159049 | 6402062 | Y | 12 |
+-------------------+-------------+-----------------+---------------------+
|159050 | 2677512 | Y | 12 |
+-------------------+-------------+-----------------+---------------------+
|159050 | 6349382 | Y | 12 |
+-------------------+-------------+-----------------+---------------------+
|159050 | 6378137 | Y | 12 |
+-------------------+-------------+-----------------+---------------------+
|159051 | 2336197 | N | 12 |
+-------------------+-------------+-----------------+---------------------+
|159051 | 6349293 | N | 12 |
+-------------------+-------------+-----------------+---------------------+
|159051 | 6350682 | N | 12 |
+-------------------+-------------+-----------------+---------------------+
|159051 | 6367895 | N | 12 |
+-------------------+-------------+-----------------+---------------------+
|159060 | yyyyyy | Y | 12 |
+-------------------+-------------+-----------------+---------------------+
IsAccntClosed column indicates if the account is Open (Y) or account is closed (Y).
I need to select Record_ID and cust_no for only those rows for which which Record_Id satisfies one of the below condition :
1. Only one cust account is open , there might be one or multiple closed customers
2. No open customer and only one closed customer
Expected output :
159045 2439123
159048 9513035
159049 2398524
159060 yyyyyy
A query like this would take each row as a single group and the count will come as 1
select RECORD_ID, CUST_NO, IsAccntClosed, count(IsAccntClosed), Code
from table1
group by RECORD_ID, CUST_NO, IsAccntClosed, Code
Any suggestions on how this query could be written to get the expected output?
Being IsAccntClosed a CHAR column, you should be able to get what you want with a query like this:
SELECT a.record_id,
(CASE
WHEN a.CountOpen=1 THEN a.CustNoOpen
ELSE a.CustNoClosed
END) AS cust_no
FROM (
SELECT b.record_id,
MAX(CASE WHEN b.IsAccntClosed='N' THEN b.cust_no ELSE NULL END) AS CustNoOpen ,
SUM(CASE WHEN b.IsAccntClosed='N' THEN 1 ELSE 0 END) AS CountOpen ,
MAX(CASE WHEN b.IsAccntClosed='Y' THEN b.cust_no ELSE NULL END) AS CustNoClosed,
SUM(CASE WHEN b.IsAccntClosed='Y' THEN 1 ELSE 0 END) AS CountClosed
FROM table1 b
GROUP BY b.record_id
) a
WHERE a.CountOpen=1 OR (a.CountOpen=0 AND a.CountClosed=1)
The inner query is grouping the table. It counts the open and closed accounts and takes one (random) cust_no of any of the closed accounts and one (random) of any of the open accounts, per group.
The outer query filters the data and cleans everything up, placing the open or closed cust_no in the output result column.
Notice that the WHERE condition of the outer query has the collateral effect that, since you are looking for records that have just a single open or a single closed account, those random cust_no which have been selected by the inner query, are now significant.
EDIT: I fixed the query and tested it on SQLFiddle.
In the below I added another record:
insert into tbl values (159060, 'zzzzzz', 'N', 12);
to illustrate what would happen if a record_id has just one open cust_no and just one closed cust_no. Note how in the result the cust_no returned is the zzzzz one, because that account is open, which you mentioned wanting to take precendence over closed, in the event of a tie 1:1 (zzzzzz should take over yyyyyy in this case, because yyyyyy is closed whereas zzzzzz is open)
Fiddle: http://sqlfiddle.com/#!4/5cb60/1/0
with one_open as
(select record_id
from tbl
where IsAccntClosed = 'N'
group by record_id
having count(distinct cust_no) = 1),
one_closed as
(select record_id
from tbl
where IsAccntClosed = 'Y'
group by record_id
having count(distinct cust_no) = 1),
bothy as
(select record_id from one_open intersect select record_id from one_closed)
select *
from tbl
where (record_id in (select record_id from one_open) and
IsAccntClosed = 'N')
or (record_id not in (select record_id from one_open) and
record_id in (select record_id from one_closed) and
IsAccntClosed = 'Y' and
record_id not in (select record_id from bothy))
select
record_id,
cust_no
from (
select
record_id,
cust_no,
count(case when isAccntClosed='Y' then 1 else null end)
over (partition by record_id) closed_accounts,
count(case when isAccntClosed='N' then 1 else null end)
over (partition by record_id) open_accounts
from
table1
)
where (open_accounts = 1)
or (open_accounts = 0 and closed_accounts = 1)
You can do this with conditional aggregation:
select RECORD_ID,
(case when sum(case when IsAccntClosed = 'N' then 1 else 0 end) = 1
then max(case when IsAccntClosed = 'N' then max(CUST_NO) end)
else max(CUST_NO)
end) as cust_no
from table1
group by RECORD_ID
having sum(case when IsAccntClosed = 'N' then 1 else 0 end) = 1 or
(sum(case when IsAccntClosed = 'N' then 1 else 0 end) = 0 and
sum(case when IsAccntClosed = 'Y' then 1 else 0 end) = 1
)
It is probably easier to understand the logic using subqueries:
select recordId,
(case when numOpen > 0 then OpenCustNo else closedCustNo end) as CustNo
from (select t1.RecordId, sum(case when IsAccntClosed = 'N' then 1 else 0 end) as numOpen,
sum(case when IsAccntOpen = 'N' then 1 else 0 end) as numClosed,
max(case when IsAccntClosed = 'N' then cust_no end) as OpenCustNo,
max(case when IsAccntClosed = 'Y' then cust_no end) as ClosedCustNo
from table1 t1
group by record_id
) r
where numOpen = 1 or numOpen = 0 and numClosed = 1;