Summing outputs from a case statement - sql

I have a query like this:
SELECT
case [Group]
when 1 then 'in'
when 0 then 'out'
end as traffic
FROM [GW_Test_Back_Up].[dbo].[ARC_Calls_ReportView]
Which creates a new column with many rows containing in/out for traffic, but what I really want is only two rows, one for the sum of the in's and the other for the sum of the out's. I am stuck on how I would do this.

I do believe you are after:
SELECT
SUM(CASE WHEN [Group] = 1 then 1 ELSE 0 END ) AS InCount,
SUM(CASE WHEN [Group] = 0 then 1 ELSE 0 END ) AS OutCount
FROM [GW_Test_Back_Up].[dbo].[ARC_Calls_ReportView]
Or maybe this:
SELECT 'InCount' AS Type,
SUM(CASE WHEN [Group] = 1 then 1 ELSE 0 END ) AS InCount
FROM [GW_Test_Back_Up].[dbo].[ARC_Calls_ReportView]
UNION ALL
SELECT 'OutCount' AS Type,
SUM(CASE WHEN [Group] = 0 then 1 ELSE 0 END ) AS OutCount
FROM [GW_Test_Back_Up].[dbo].[ARC_Calls_ReportView]
EDIT:
SELECT
CASE WHEN m.InCount > 10 THEN 'High' ELSE 'Low' END AS InCountStatus
CASE WHEN m.OutCount > 10 THEN 'High' ELSE 'Low' END AS OutCountStatus
FROM
(
SELECT
SUM(CASE WHEN [Group] = 1 then 1 ELSE 0 END ) AS InCount,
SUM(CASE WHEN [Group] = 0 then 1 ELSE 0 END ) AS OutCount
FROM [GW_Test_Back_Up].[dbo].[ARC_Calls_ReportView]
) m

Related

Query to get a output in desired format

Proc type add sub multi div
1 A 1 0 1 1
1 B 2 2 0 1
Output should be in the format
Proc Aadd Asub Amulti Adiv Badd Bsub Bmulti Bdiv
1 1 0 1 1 2 2 0 1
A simple conditional aggregation should do the trick
Select Proc
,Aadd = max( case when type='A' then add else 0 end)
,Asub = max( case when type='A' then sub else 0 end)
,Amuti = max( case when type='A' then multi else 0 end)
,Adiv = max( case when type='A' then div else 0 end)
,Badd = max( case when type='B' then add else 0 end)
,Bsub = max( case when type='B' then sub else 0 end)
,Bmuti = max( case when type='B' then multi else 0 end)
,Bdiv = max( case when type='B' then div else 0 end)
From YourTable
Group By Proc
Another approach using CTE and Joins.
declare #table table(Proce int, type char(1), addi int, sub int, multi int, div int)
insert into #table values
(1,'A', 1, 0, 1, 1),
(1,'B', 2, 2, 0, 1);
;with cte_a as
(
SELECT proce, max(addi) as Aadd, max(sub) as Asub, max(multi) as Amulti, max(div) as Adiv
FROM #table where type = 'A'
group by proce
),cte_b as
(
SELECT proce, max(addi) as Badd, max(sub) as Bsub, max(multi) as Bmulti, max(div) as Bdiv
FROM #table where type = 'B'
group by proce
)
SELECT a.proce,a.aAdd, a.aSub, a.Amulti, a.Adiv,b.BAdd,b.bsub, b.bmulti, b.bdiv
from cte_a as a
join cte_b as b
on a.Proce = b.Proce
proce
aAdd
aSub
Amulti
Adiv
BAdd
bsub
bmulti
bdiv
1
1
0
1
1
2
2
0
1

Hello! is that anyway to write similar query without using union?

is that anyway to write similar query without using union?
select sum(decode(p.sumsend,0,1,0)) recvcnt,
sum(decode(p.sumsend,0,1,0)*p.sumserv) recvsum
from some_table p
where p.polefilter = 5
union
select sum(decode(p.sumsend,0,1,0)) recvcnt,
sum(decode(p.sumsend,0,1,0)*p.sumserv) recvsum
from some_table p
where p.polefilter != 5
If you are OK with having all 4 columns on one row, then one option is conditional aggregation:
select
sum(case when polefilter = 5 and sumsend = 0 then 1 else 0 end) recvcnt1,
sum(case when polefilter = 5 and sumsend = 0 then 1 else 0 end * sumserv) recvsum1,
sum(case when polefilter <> 5 and sumsend = 0 then 1 else 0 end) recvcnt2,
sum(case when polefilter <> 5 and sumsend = 0 then 1 else 0 end * sumserv) recvsum2
from some_table p
where polefilter is not null
On the other hand, if you want two rows in the resultset, then you can use aggregation and a case expression to define the groups:
select
case when polefilter = 5 then 1 else 0 end as polefilter_is_5
sum(case when sumsend = 0 then 1 else 0 end) recvcnt,
sum(case when sumsend = 0 then 1 else 0 end * sumserv) recvsum1
from some_table p
where p.polefilter is not null
group by case when polefilter = 5 then 1 else 0 end
Note that I changed the decode() functions to case expressions; both do the same thing, but the latest is standard SQL (and is somehow more flexible).
A query like the one below should work. Please provide sample data and expected output when asking a question next time.
SELECT SUM (CASE WHEN p.sumsend = 0 THEN 1 ELSE 0 END) recvcnt,
SUM (CASE WHEN p.sumsend = 0 THEN 1 ELSE 0 END * p.sumserv) recvsum
FROM some_table p
GROUP BY CASE p.polefilter WHEN 5 THEN 1 ELSE 0 END;

Is there a way to rewrite this statement without sub queries?

I am trying to combine 4 queries for a monthly report so that I don't have to run them seperately. Our internal accounting software appears doesn't support sub queries so this statement doesn't work.
select left(salesgroupcode,4) as "Sales Group",
count(Number_of_products),
count(Number_of_discontinued),
count(Number_not_uploaded),
count(Number_sitting)
from (select
case when quantityavailable > 1 then 1 end Number_of_products,
case when quantityavailable > 1 and discontinued = true then 1 end Number_of_discontinued,
case when quantityavailable > 1 and z_datefirstuploaded is null then 1 end Number_not_uploaded,
case when quantityavailable > 1 and z_datefirstuploaded is null and dateoflastsale <= '01/01/2019' then 1 end Number_sitting
from icprod
) icprod
I don't have any other info about the specific rules etc that the software allows so I'm happy to try anything.
Thanks in advance.
Any help is appreciated
Yes, it is possible:
select left(salesgroupcode,4) as "Sales Group",
count(*),
count(case when discontinued = true then 1 end ),
count(case when z_datefirstuploaded is null then 1 end),
count(case when z_datefirstuploaded is null and dateoflastsale <= '01/01/2019')
from icprod
where quantityavailable > 1
group by left(salesgroupcode,4)
Just use conditional aggregation:
select sum(case when quantityavailable > 1 then 1 else 0 end ) as Number_of_products,
sum(case when quantityavailable > 1 and discontinued = true then 1 else 0 end) as Number_of_discontinued,
sum(case when quantityavailable > 1 and z_datefirstuploaded is null then 1 else 0 end) as Number_not_uploaded,
sum(case when quantityavailable > 1 and z_datefirstuploaded is null and dateoflastsale <= '2019-01-01' then 1 else 0 end) as Number_sitting
from icprod;
Notes that I changed the date constant to be ISO 8601 standard format. In some databases, you may need to precede that with date.
This can in turn be simplified to:
select count(*) as Number_of_products,
sum(case when discontinued = true then 1 else 0 end) as Number_of_discontinued,
sum(case when z_datefirstuploaded is null then 1 else 0 end) as Number_not_uploaded,
sum(case when z_datefirstuploaded is null and dateoflastsale <= '2019-01-01' then 1 else 0 end) as Number_sitting
from icprod
where quantityavailable > 1

Create and classify a row based on column values

I am attempting to assign a classification to a row of data based on whether certain values exist. Utilizing the sample code below I have gotten to a place where I've gotten stuck.
proc sql;
create table test
(id char(4),
task char(4),
id2 char(4),
status char(10),
seconds num);
insert into test
values('1','A','1','COMP',15)
values('1','B','2','WORK',20)
values('1','C','3','COMP',50)
values('1','D','3','COMP',null)
values('2','A','1','COMP',15)
values('2','B','2','COMP',520)
values('2','C','2','COMP',NULL)
values('2','D','3','COMP',221)
values('2','E','3','COMP',null)
values('2','F','3','COMP',null);
proc sql;
create table test2 as
select
ID,
ID2,
STATUS,
SUM(SECONDS) AS SECONDS,
sum(case when task='A' THEN 1 ELSE 0 END) AS A,
sum(case when task='B' THEN 1 ELSE 0 END) AS B,
sum(case when task='C' THEN 1 ELSE 0 END) AS C,
sum(case when task='D' THEN 1 ELSE 0 END) AS D,
sum(case when task='E' THEN 1 ELSE 0 END) AS E,
sum(case when task='F' THEN 1 ELSE 0 END) AS F
from
test
GROUP BY
ID,
ID2,
STATUS
;
quit;
Ultimately I would like to classify each row that gets created in the second step 'test2' to have a column that looks to the values in each lettered column(A-F) and Label them as such. So when the Row has a 1 in Column A only, it would be labeled 'A' but when a row has a 1 in multiple columns like 'D', 'E' and 'F' I would like it to be labeled as D_E_F.
Best way to do this is in a DATA STEP:
data test3;
format classifier $32.;
set test2;
array vars[6] A B C D E F;
classifier = "";
do i=1 to 6;
if vars[i] then
classifier = catx("_",classifier,vname(vars[i]));
end;
drop i;
run;
I create a character variable CLASSIFIER with length 32.
I define an array that groups the columns A through F. This allows me to loop over those columns easily.
Initialize the CLASSIFIER variable.
Loop over the array. If the value =1, then add the name of the variable to the CLASSIFIER string.
CATX(delim,str1,str2) concatenates str1 and str2 with the delim in the middle. It also removes whitespace.
VNAME(array[i]) returns the variable name of the variable pointed to by array[i].
Finally remove the i loop variable, unless you really want it in your output.
I know it is ugly, but you can do it with CASE statements accumulating the wanted result in another field. You have the SQL Fiddle here.
Note that if it is possible that the concatenation is empty you will have to check this condition to avoid performing the substring.
select
ID,
ID2,
STATUS,
SUM(SECONDS) AS SECONDS,
sum(case when task='A' THEN 1 ELSE 0 END) AS A,
sum(case when task='B' THEN 1 ELSE 0 END) AS B,
sum(case when task='C' THEN 1 ELSE 0 END) AS C,
sum(case when task='D' THEN 1 ELSE 0 END) AS D,
sum(case when task='E' THEN 1 ELSE 0 END) AS E,
sum(case when task='F' THEN 1 ELSE 0 END) AS F,
substring(
case when sum(case when task='A' THEN 1 ELSE 0 END) = 1 then '_A' else '' end
+ case when sum(case when task='B' THEN 1 ELSE 0 END) = 1 then '_B' else '' end
+ case when sum(case when task='C' THEN 1 ELSE 0 END) = 1 then '_C' else '' end
+ case when sum(case when task='D' THEN 1 ELSE 0 END) = 1 then '_D' else '' end
+ case when sum(case when task='E' THEN 1 ELSE 0 END) = 1 then '_E' else '' end
+ case when sum(case when task='F' THEN 1 ELSE 0 END) = 1 then '_F' else '' end,
2, len(case when sum(case when task='A' THEN 1 ELSE 0 END) = 1 then '_A' else '' end
+ case when sum(case when task='B' THEN 1 ELSE 0 END) = 1 then '_B' else '' end
+ case when sum(case when task='C' THEN 1 ELSE 0 END) = 1 then '_C' else '' end
+ case when sum(case when task='D' THEN 1 ELSE 0 END) = 1 then '_D' else '' end
+ case when sum(case when task='E' THEN 1 ELSE 0 END) = 1 then '_E' else '' end
+ case when sum(case when task='F' THEN 1 ELSE 0 END) = 1 then '_F' else '' end) - 1) as wantedOutput
from
test
GROUP BY
ID,
ID2,
STATUS

Sum data for many different results for same field

I am trying to find a better way to write this sql server code 2008. It works and data is accurate. Reason i ask is that i will be asked to do this for several other reports going forward and want to reduce the amount of code to upkeep going forward.
How can i take a field where i sum for the yes/no/- (dash) in each field without doing an individual sum as i have in code. Each table is a month of detail data which i sum using in a CTE. i changed the table name for each month and Union All to put data together. Is there a better way to do this. This is a small sample of code. Thanks for the help.
WITH H AS (
SELECT 'August' AS Month_Name
, SUM(CASE WHEN G.FFS = '-' THEN 1 ELSE 0 END) AS FFS_Dash
, SUM(CASE WHEN G.FFS = 'Yes' THEN 1 ELSE 0 END) AS FFS_Yes
, SUM(CASE WHEN G.FFS = 'No' THEN 1 ELSE 0 END) AS FFS_No
, SUM(CASE WHEN G.DNA = '-' THEN 1 ELSE 0 END) AS DNA_Dash
, SUM(CASE WHEN G.DNA = 'Yes' THEN 1 ELSE 0 END) AS DNA_Yes
, SUM(CASE WHEN G.DNA = 'No' THEN 1 ELSE 0 END) AS DNA_No
FROM table08 G )
, G AS (
SELECT 'July' AS Month_Name
, SUM(CASE WHEN G.FFS = '-' THEN 1 ELSE 0 END) AS FFS_Dash
, SUM(CASE WHEN G.FFS = 'Yes' THEN 1 ELSE 0 END) AS FFS_Yes
, SUM(CASE WHEN G.FFS = 'No' THEN 1 ELSE 0 END) AS FFS_No
, SUM(CASE WHEN G.DNA = '-' THEN 1 ELSE 0 END) AS DNA_Dash
, SUM(CASE WHEN G.DNA = 'Yes' THEN 1 ELSE 0 END) AS DNA_Yes
, SUM(CASE WHEN G.DNA = 'No' THEN 1 ELSE 0 END) AS DNA_No
FROM table07 G )
select * from H
UNION ALL
select * from G
How about:
SELECT Month_Name,
SUM(CASE WHEN G.FFS = '-' THEN 1 ELSE 0 END) AS FFS_Dash,
SUM(CASE WHEN G.FFS = 'Yes' THEN 1 ELSE 0 END) AS FFS_Yes,
SUM(CASE WHEN G.FFS = 'No' THEN 1 ELSE 0 END) AS FFS_No,
SUM(CASE WHEN G.DNA = '-' THEN 1 ELSE 0 END) AS DNA_Dash,
SUM(CASE WHEN G.DNA = 'Yes' THEN 1 ELSE 0 END) AS DNA_Yes,
SUM(CASE WHEN G.DNA = 'No' THEN 1 ELSE 0 END) AS DNA_No
FROM ((select 'July' as Month_Name, G.*
from table07 G
) union all
(select 'August', H.*
from table08 H
)
) gh
GROUP BY Month_Name;
However, having tables with the same structure is usually a sign of poor database design. You should have a single table with a column representing the month.