SUM(CASE WHEN) with condition of another aggregate function - sql

I'm fairly new to SQL and can't seem to get my query doing what I want it to do.
I want the sum of one column based on the occurrence of another condition.
My table looks something like this:
ID
Location
Scan_Code
Scan_Date
1
PlaceA
01
2021-02-01
1
PlaceA
02
2021-02-01
2
PlaceA
01
2021-02-01
2
PlaceA
02
2021-02-02
3
PlaceB
01
2021-02-01
3
PlaceB
02
2021-02-01
3
PlaceB
01
2021-02-02
3
PlaceB
02
2021-02-02
4
PlaceB
02
2021-02-02
The result should sum the occurrence of Scan 01 on any given Date per Location and sum of Scan 02 IF there was a Scan 01 on the same day for that ID.
Expected result for the table above
|Scan_Date |Location|Sum_Scan01|ConditionalSum02|
|----------|--------|----------|----------------|
|2021-02-01|PlaceA |2 |1 |
|2021-02-01|PlaceB |1 |1 |
|2021-02-02|PlaceB |1 |1 |
My query currently looks like this and sums all of scan 02 regardless of occurrence of scan 01 and I can't figure out how I can include that condition as I cant just repeat the first one in the second case:
select
scan_date,
Location,
SUM(case when scan_code EQ '01' then 1 else 0 end) as Scan01,
SUM(case when scan_code EQ '02' then 1 else 0 end) as Scan02
from ScanDB
where scan_date between '?From' and '?To'
group by scan_date,Location
Thanks a lot from a new user.

You probably need nested aggregation, this should work:
with cte as
( select
id, -- include id in inital calculation
scan_date,
Location,
SUM(case when scan_code = '01' then 1 else 0 end) as cntScan01,
SUM(case when scan_code = '02' then 1 else 0 end) as cntScan02
from ScanDB
where scan_date between '?From' and '?To'
group by id,scan_date,Location
)
select
scan_date,
Location,
SUM(cntScan01) as Scan01,
-- check if 01 exists for same id
SUM(case when cntScan01 > 0 then cntScan02 else 0 end) as Scan02
from cte
group by scan_date,Location

I would be inclined to use window functions:
select scan_date, Location,
sum(case when scan_code EQ '01' then 1 else 0 end) as Scan01,
sum(case when num_id_01 > 0 and scan_code EQ '02' then 1 else 0 end) as Scan02
from (select s.*,
sum(case when scan_code EQ '01' then 1 else 0 end) over (partition by id, scan_date) as num_id_01
from ScanDB s
where s.scan_date between '?From' and '?To'
) s
group by scan_date, Location;

Related

Count records by Grouping a period

I have a table that stores per day if a user worked or if he was on vacation based on a value.
Example table, Value = 1 -> WorkDay, Value = 2 -> Vacation:
User | Day | Value
--------|------------|-------
user-1 | 2021-01-01 | 1
user-1 | 2021-01-02 | 1
user-1 | 2021-01-03 | 1
user-1 | 2021-01-04 | 1
user-1 | 2021-01-05 | 2
user-1 | 2021-01-06 | 2
...
I'll like to convert this table to this (Using the simple example above):
User | Year | Month | WorkDay | Vacation
--------|------|-------|---------|---------
user-1 | 2021 | 01 | 4 | 2
...
I tried using group by, subqueries and case, but the whole thing become a mess.
SELECT
YEAR(Day),
MONTH(DAY),
User,
...
From Table1
Group By YEAR(Day), MONTH(DAY), User
Just use conditional aggregation:
select year(day), month(day),
sum(case when value = 1 then 1 else 0 end) as workday,
sum(case when value = 2 then 1 else 0 end) as vacation
from table1
group by year(day), month(day)
You can use conditional aggregation as below:
select User,
year(day),
month(day),
sum(case when value = 1 then 1 else 0 end) as WorkDay,
sum(case when value = 2 then 1 else 0 end) as Vacation
from table1
group by User, year(day), month(day)
DB-Fiddle:
Schema and insert statements:
create table table1([User] varchar(50), Day date, Value int);
insert into table1 values('user-1' , '2021-01-01' , 1);
insert into table1 values('user-1' , '2021-01-02' , 1);
insert into table1 values('user-1' , '2021-01-03' , 1);
insert into table1 values('user-1' , '2021-01-04' , 1);
insert into table1 values('user-1' , '2021-01-05' , 2);
insert into table1 values('user-1' , '2021-01-06' , 2);
Query:
select [User] as "user",
year(day) as "year",
month(day) as "month",
sum(case when value = 1 then 1 else 0 end) as WorkDay,
sum(case when value = 2 then 1 else 0 end) as Vacation
from table1
group by [User], year(day), month(day)
GO
Output:
user
year
month
WorkDay
Vacation
user-1
2021
1
4
2
db<fiddle here

Using SQL, how to calculate count of rows for each ID(column) for each month by using only datetime and put them in monthly columns?

I am relatively new to SQL. I have a dataset as follows:
'ID' 'date'
1 2016-01-01 01:01:06
2 2016-01-02 02:02:07
1 2016-01-03 03:03:08
3 2016-04-04 04:04:09
2 2016-04-05 05:05:00
I want to obtain smth like this:
'ID' 'Count: Jan' 'Count: Feb' 'Count: March' 'Count: April'
1 2 0 0 0
2 1 0 1 0
3 0 0 0 1
I really have no idea how handle this. I could put the data creating a column "month" and another column "count" but I want to be able to have a table like this.
Thanks in advance
You ca use conditional aggregation:
select id,
sum(case when month(date) = 1 then 1 else 0 end) as cnt_jan,
sum(case when month(date) = 2 then 1 else 0 end) as cnt_feb,
. . .
sum(case when month(date) = 12 then 1 else 0 end) as cnt_dec
from t
group by id;

Group by datepart and find total count of individual values of each record

This is table structure;
ID Score Valid CreatedDate
1 A 1 2018-02-19 23:33:10.297
2 C 0 2018-02-19 23:32:40.700
3 B 1 2018-02-19 23:32:30.247
4 A 1 2018-02-19 23:31:37.153
5 B 0 2018-02-19 23:25:08.667
...
I need to find total number of each score and valid in each month
I mean final result should be like
Month A B C D E Valid(1) NotValid(0)
January 123 343 1021 98 12 1287 480
February 516 421 321 441 421 987 672
...
This is what I tried;
SELECT DATEPART(year, CreatedDate) as Ay,
(select count(*) from TableResults where Score='A') as 'A',
(select count(*) from TableResults where Score='B') as 'B',
...
FROM TableResults
group by DATEPART(MONTH, CreatedDate)
but couldn't figure how to calculate all occurrence of scores on each month.
Use conditional aggregation.
SELECT DATEPART(year, CreatedDate) as YR
, DATEPART(month, CreatedDate) MO
, sum(Case when score = 'A' then 1 else 0 end) as A
, sum(Case when score = 'B' then 1 else 0 end) as B
, sum(Case when score = 'C' then 1 else 0 end) as C
, sum(Case when score = 'D' then 1 else 0 end) as D
, sum(Case when score = 'E' then 1 else 0 end) as E
, sum(case when valid = 1 then 1 else 0 end) as Valid
, sum(case when valid = 0 then 1 else 0 end) as NotValid
FROM TableResults
GROUP BY DATEPART(MONTH, CreatedDate), DATEPART(year, CreatedDate)
I'm not a big fan of queries in the select; I find they tend to cause performance problems in the long run. Since we're aggregating here I just applied the conditional logic to all the columns.

How to count sql from one column, and display it in two column

I have a table like this:
idrecord | date
----------------------------------------------
INC-20140308102029 | 2014-03-08 00:00:00.000
INC-20140308102840 | 2014-03-06 00:00:00.000
INC-20140310164404 | 2014-03-10 00:00:00.000
INC-20140311075714 | 2014-03-09 00:00:00.000
NRM-20140310130512 | 2014-04-02 00:00:00.000
NRM-20140311134720 | 2014-03-11 00:00:00.000
USF-20140317212232 | 2014-03-17 00:00:00.000
USF-20140321075402 | 2014-03-18 00:00:00.000
USF-20140321083137 | 2014-03-21 00:00:00.000
how to count this table and display result like this:
month | INC | NRM | USF
march | 4 | 1 | 3
April | 0 | 1 | 0
Thank you
You'd use case to count 1 or zero depending on the string matching or not. Use sum to count.
select
extract(month from thedate) as whichmonth,
sum( case when idrecord like 'INC%' then 1 else 0 end) as inc,
sum( case when idrecord like 'NRM%' then 1 else 0 end) as nrm,
sum( case when idrecord like 'USF%' then 1 else 0 end) as usf
from mytable
group by extract(month from thedate);
The function to extract the month from the date may vary from dbms to dbms. Look the appropriate function up in Google, if extract doesn't work for you.
Don't use the name date for a column. Date is a reserved word in SQL.
Try this
SELECT convert(char(3), date, 0) AS Month,
SUM(Case when LEFT(idrecord,3) = 'INC' then 1 else 0 end) as 'INC',
SUM(Case when LEFT(idrecord,3) = 'NRM' then 1 else 0 end) as 'NRM',
SUM(Case when LEFT(idrecord,3) = 'USF' then 1 else 0 end) as 'USF'
FROM Table1
Group By convert(char(3), date, 0)
Fiddle Demo
or:
SELECT datename(mm, date) AS Month,
SUM(Case when LEFT(idrecord,3) = 'INC' then 1 else 0 end) as 'INC',
SUM(Case when LEFT(idrecord,3) = 'NRM' then 1 else 0 end) as 'NRM',
SUM(Case when LEFT(idrecord,3) = 'USF' then 1 else 0 end) as 'USF'
FROM Table1
Group By datename(mm, date)
Fiddle Demo
Output:
month | INC | NRM | USF
march | 4 | 1 | 3
April | 0 | 1 | 0
try this one
select month (date) as month,
count( case when idrecord like 'INC%' then 1 else 0 end) as inc,
count( case when idrecord like 'NRM%' then 1 else 0 end) as nrm,
count( case when idrecord like 'USF%' then 1 else 0 end) as usf
from table
group by month;

SQL query to calculate total per month as a column

I am stuck on a SQL query. I am using PostgreSQL. I need to get the total for each month for all states.
table A
--------------------------------------------------------
created | Name | Agent_id | Total
--------------------------------------------------------
3/14/2013 | Harun | 1A | 5
3/14/2013 | Hardi | 2A | 20
4/14/2013 | Nizar | 3A | 30
5/14/2013 | moyes | 4A | 20
table B
----------------------------
Agent_id| state_id
----------------------------
1A | 1
2A | 1
3A | 1
4A | 2
table C
----------------------------
state_id | State
----------------------------
1 | Jakarta
2 | Singapore
3 | Kuala lumpur
DESIRED RESULT:
-----------------------------------------------------------------------------------------------
No |State | Januari | February | March | April | Mei ... December| Total
-----------------------------------------------------------------------------------------------
1 |Jakarta |0 |0 |25 | 30 | 0 ... | 55
2 |Singapore |0 |0 | 0 | 0 | 20 ... | 20
3 |Kuala Lumpur |0 |0 | 0 | 0 | 0 ... | 0
to have all state with no data in table A / B you have to use OUTER JOIN
to complete #bma answer
select
no,
state,
sum(case when month = 1 then total else 0 end) as januari,
sum(case when month = 2 then total else 0 end) as februari,
sum(case when month = 3 then total else 0 end) as mars,
sum(case when month = 4 then total else 0 end) as april,
sum(case when month = 5 then total else 0 end) as may,
sum(case when month = 6 then total else 0 end) as juni,
sum(case when month = 7 then total else 0 end) as juli,
sum(case when month = 8 then total else 0 end) as august,
sum(case when month = 9 then total else 0 end) as september,
sum(case when month = 10 then total else 0 end) as october,
sum(case when month = 11 then total else 0 end) as november,
sum(case when month = 12 then total else 0 end) as december,
sum(coalesce(total,0)) as total
from (
select
c.state_id as no,
extract(month from created) as month,
state,
sum(total) as total
from tablec c
left join tableb b on ( b.state_id = c.state_id)
left join tablea a on ( a.agent_id = b.agent_id)
group by c.state_id,state,month
) sales
group by no,state;
SQL Fiddle demo
Actually i do not know much about postgres sql this is a try see if this works
try this
Select EXTRACT(MONTH FROM TIMESTAMP table A.created) ,
table C.State , SUM(Total) From table A , table B , table C
Where table A.Agent_id = table B.Agent_id
And table B.state_id = table C.state_id
Group by table C.State , EXTRACT(MONTH FROM TIMESTAMP table A.created);
Something like the following should give you results like your sample results. I'm not sure what the "No" column was though. This query is untested.
select state,
sum(case when mm = 1 then total else 0 end) as jan,
sum(case when mm = 2 then total else 0 end) as feb,
sum(case when mm = 3 then total else 0 end) as mar,
sum(case when mm = 4 then total else 0 end) as apr,
sum(case when mm = 5 then total else 0 end) as may,
sum(case when mm = 6 then total else 0 end) as jun,
sum(case when mm = 7 then total else 0 end) as jul,
sum(case when mm = 8 then total else 0 end) as aug,
sum(case when mm = 9 then total else 0 end) as sep,
sum(case when mm = 10 then total else 0 end) as oct,
sum(case when mm = 11 then total else 0 end) as nov,
sum(case when mm = 12 then total else 0 end) as dec,
sum(total) as total
from (
select extract(month from created) as mm,
state,
sum(total) as total
from table_a
group by state,mm
) s
group by state;