SQL Query group by Postcode multiple Sums - sql

I have following data:
ID
Weight
Postcode
Year
1
23
56222
2022
2
24
56332
2022
3
50
56442
2022
4
22
62331
2022
5
80
72130
2022
and i want to query it that i get the data like this:
Grouped by Postcode and splitted in different weight ranges.
and then just Count of the amount of entrys.
Postcode/Weight
0-20
21-40
41-60
61-80
81-100
56
0
2
1
0
0
62
0
1
0
0
0
72
0
0
0
1
0
Is there any way to query this in SQL?

Try this one.
Query:
SELECT
p.postcode,
COUNT(p20.id) as "0-20",
COUNT(p40.id) as "21-40",
COUNT(p60.id) as "41-60",
COUNT(p80.id) as "61-80",
COUNT(p100.id) as "81-100"
FROM packs p
LEFT JOIN packs p20 ON p20.postcode=p.postcode AND p20.weight < 20
LEFT JOIN packs p40 ON p40.postcode=p.postcode AND p40.weight >= 21 AND p40.weight <= 40
LEFT JOIN packs p60 ON p60.postcode=p.postcode AND p60.weight >= 41 AND p60.weight <= 60
LEFT JOIN packs p80 ON p80.postcode=p.postcode AND p80.weight >= 61 AND p80.weight <= 80
LEFT JOIN packs p100 ON p100.postcode=p.postcode AND p100.weight >= 81 AND p100.weight <= 100
GROUP by postcode;
Result:
Table

Related

proc sql statement to sum on values/rows that match a condition

I have a data table like below:
Table 1:
ROWID PERSONID YEAR pidDifference TIMETOEVENT DAYSBETVISIT
10 111 2009 . 100 .
110 120 2009 9 10 .
231 120 2009 0 20 10
222 120 2010 0 40 20
221 222 2009 102 10 30
321 222 2009 0 30 20
213 222 2009 0 10 20
432 321 2009 99 10 0
211 432 2009 111 20 10
212 432 2009 0 20 0
I want to sum over the DAYSBETVISIT column only when the pidDifference value is 0 for each PERSONID. So I wrote the following proc sql statement.
proc sql;
create table table5 as
(
select rowid, YEAR, PERSONID, pidDifference, TIMETOEVENT, DAYSBETVISIT,
SUM(CASE WHEN PIDDifference = 0 THEN DaysBetVisit ELSE 0 END)
from WORK.Table4_1
group by PERSONID,TIMETOEVENT, YEAR
);
quit;
However, the result I got was not summing the DAYSBETVISIT values in rows where PIDDifference = 0 within the same PERSONID. It just output the same value as was present in DAYSBETVISIT in that specific row.
Column that I NEED (sumdays) but don't get with above statement (showing the resultant column using above statement as OUT:
ROWID PERSONID YEAR pidDifference TIMETOEVENT DAYSBETVISIT sumdays OUT
10 111 2009 . 100 . 0 0
110 120 2009 9 10 . 0 0
231 120 2009 0 20 10 30 10
222 120 2010 0 40 20 30 20
221 222 2009 102 10 30 0 0
321 222 2009 0 30 20 40 20
213 222 2009 0 10 20 40 20
432 321 2009 99 10 0 0 0
211 432 2009 111 20 10 0 0
212 432 2009 0 20 0 0 0
I do not know what I am doing wrong.
I am using SAS EG Version 7.15, Base SAS version 9.4.
For your example data it looks like you just need to use two CASE statements. One to define which values to SUM() and another to define whether to report the SUM or not.
proc sql ;
select personid, piddifference, daysbetvisit, sumdays
, case when piddifference = 0
then sum(case when piddifference=0 then daysbetvisit else 0 end)
else 0 end as WANT
from expect
group by personid
;
quit;
Results
pid
PERSONID Difference DAYSBETVISIT sumdays WANT
--------------------------------------------------------
111 . . 0 0
120 0 10 30 30
120 0 20 30 30
120 9 . 0 0
222 0 20 40 40
222 0 20 40 40
222 102 30 0 0
321 99 0 0 0
432 0 0 0 0
432 111 10 0 0
SAS proc sql doesn't support window functions. I find the re-merging aggregations to be a bit difficult to use, except in the obvious cases. So, use a subquery or join and group by:
proc sql;
create table table5 as
select t.rowid, t.YEAR, t.PERSONID, t.pidDifference, t.TIMETOEVENT, t.DAYSBETVISIT,
tt.sum_DaysBetVisit
from WORK.Table4_1 t left join
(select personid, sum(DaysBetVisit) as sum_DaysBetVisit
from WORK.Table4_1
group by personid
having min(pidDifference) = max(pidDifference) and min(pidDifference) = 0
) tt
on tt.personid = t.personid;
Note: This doesn't handle NULL values for pidDifference. If that is a concern, you can add count(pidDifference) = count(*) to the having clause.

SQL LOGIC using 3conditions

course_completions CC
id coursemodid userid state timemodified
370 23 2 1 1433582890
329 24 89 1 1427771915
333 30 39 1 1428309816
332 32 39 1 1428303307
327 33 40 1 1427689703
328 34 89 1 1427710711
303 35 41 1 1410258482
358 36 99 1 1432020067
365 25 2 1 1433142455
304 26 69 1 1410717866
353 37 95 1 1430387005
416 38 2 1 1438972465
300 27 70 1 1409824001
302 29 74 1 1412055704
297 30 2 1 1409582123
301 133 41 1 1410255923
336 133 91 1 1428398435
364 133 40 1 1433142348
312 133 85 1 1425863621
course_modules CM
id course
23 6
24 6
25 6
26 6
27 6
28 6
29 8
30 8
31 8
32 8
33 8
34 5
35 5
36 5
37 5
38 5
39 9
40 9
41 9
course_mod_settings CMS
id course modinstance
27 8 30
28 8 31
29 8 32
30 8 33
31 6 23
32 6 24
33 6 25
34 6 26
35 6 27
36 6 28
37 9 39
38 9 40
39 9 41
I need the count of each user has Completed modules, Inprocess modules and Notstarted modules for each course, where getting the count of userids from table CC by taking courseia from table CM, get number of modules that an user has completed from each course.
(A course can have morethan one module and a course can have number of users attempted all modules, few modules or not attempted at all).
So, I need number of users - has done number of modules - in a course. (3 logics)
Completed.Users means : If number of modules attempted is equal to number of modinstance from table CMS (ex: no. of modules attempted by a user per course= 9, no.modinstance = 9. Because 7 is not equal to 9, They are completed.)
Inprocess.Users means : Number of modules attempted should be >0, but not equal to [count(modinstance) per course] (ex: no. of modules attempted by a user per course= 7 , no.modinstance = 9. Because 7 is not equal to 9, They are Inprocess.)
Notstarted.Users means : Number of modules attempted should be equal to 0, (ex: no. of modules attempted by a user per course= 0. They are Notstarted).
OUTPUT :
Course No.Completed.Users No.Inprocess.Users No.Notstarted.Users
5 65 32 6
6 40 12 15
8 43 56 0
9 0 7 9
Sir, this is a very critical logic that I was trying, I couldn't get a solution. I hope stackoverflow developers could help me out. I tried with my query :
SELECT cm.course AS "Course",
(CASE WHEN
(SELECT count(cms.id) FROM course_mod_settings cms) =
(SELECT count(cmc.coursemodid) FROM course_completions cc JOIN course_modules cm ON cmc.coursemodid = cm.id WHERE cmc.state=1 )
THEN COUNT(SELECT count(cmc.coursemodid) FROM course_completions cc JOIN course_modules cm ON cmc.coursemodid = cm.id WHERE cmc.state=1 ) END) AS "No.Completed.Users",
(CASE WHEN
(SELECT count(cms.id) FROM course_mod_settings cms) > 0 AND
(SELECT count(cms.id) FROM course_mod_settings cms) !=
(SELECT count(cmc.coursemodid) FROM course_completions cc JOIN course_modules cm ON cmc.coursemodid = cm.id WHERE cmc.state=1 )
THEN COUNT(SELECT count(cmc.coursemodid) FROM course_completions cc JOIN course_modules cm ON cmc.coursemodid = cm.id WHERE cmc.state=1 ) END) AS "No.Inprocess.Users",
(CASE WHEN
(SELECT count(cms.id) FROM course_mod_settings cms) = 0
THEN COUNT(SELECT count(cmc.coursemodid) FROM course_completions cc JOIN course_modules cm ON cmc.coursemodid = cm.id WHERE cmc.state=1 ) END) AS "No.Notstarted.Users"
FROM
mdl_course c
GROUP BY c.id
SQL Fiddle
SELECT course AS "Course",
SUM(CASE WHEN completion_count = module_count THEN 1 ELSE 0 END) AS "No.Completed.Users",
SUM(CASE WHEN completion_count > 0 AND completion_count < module_count THEN 1 ELSE 0 END) AS "No.Inprocess.Users",
SUM(CASE WHEN completion_count = 0 THEN 1 ELSE 0 END) AS "No.Notstarted.Users"
FROM (SELECT course, COUNT(*) AS module_count
FROM course_modules cm
GROUP BY course) course_module_counts JOIN
(SELECT cm.course AS courseid, users.id AS userid, SUM(CASE WHEN cc.state = 1 THEN 1 ELSE 0 END) completion_count
FROM ((SELECT DISTINCT userid AS id FROM course_completions) users CROSS JOIN course_modules cm) LEFT JOIN course_completions cc ON users.id = cc.userid AND cc.coursemodid = cm.id
GROUP BY cm.course, users.id) course_completion_counts
ON course_module_counts.course = course_completion_counts.courseid
GROUP BY course
gives this output, which matches the limited dataset that you provided in your question.
| course | No.Completed.Users | No.Inprocess.Users | No.Notstarted.Users |
|--------|--------------------|--------------------|---------------------|
| 5 | 0 | 5 | 7 |
| 6 | 0 | 4 | 8 |
| 8 | 0 | 4 | 8 |
| 9 | 0 | 0 | 12 |

How to get sum of the same Unit's

I have a table which contains a college's departments and their units and sub-units.
OrganizationID ParentUnit Unit ChildUnit UnitName
10 1 0 0 Education
12 1 1 0 Sports
24 1 2 0 Mathmatics
28 1 3 0 Science
35 1 3 1 Physics
51 1 4 0 Arts
66 1 4 1 Music
69 1 4 2 Painting
84 8 0 0 Business & Administration
88 8 1 0 Administration
96 8 1 1 Public Administration
107 8 1 2 Local Managements
110 8 2 0 Finance
119 8 2 1 Accounting
124 8 2 2 Marketing
I have another table which contains the student information of that college.
StudentID OrganizationID
1 12
2 12
3 24
5 28
6 35
8 51
9 66
31 69
34 96
45 88
57 96
66 107
69 110
72 69
74 124
I want to get student counts for each unit. If a studutent's Organization is a ChildUnit it should be added to current Unit. If ChildUnit is greater than0 corresponding student count should be added to same Unit For example Physics is a child of Science. Then Science student count should return 2.
My target data table should look like as the following
ParentUnit UnitName StudentCount
------------------------------------------------------
Education Sports 2
Education Mathmatics 1
Education Science 2
Education Arts 4
Business & Administration Administration 4
Business & Administration Finance 2
I have done it in programmatic way. There are many for and if loops. Then I started to think whether it could be done with a smarter sql query.
That doesn't look so difficult. You are looking for the student count per ParentUnit + Unit. Then the name for such a group is the record where the level (the ChildUnit) is zero. You get that record with a CASE construct, then use MIN or MAX, because you need an aggregate function here (there should be exactly one record per group anyhow, so MIN = MAX).
select
min(case when o.childunit = 0 then o.unitname end) as unitname,
count(*) as studentcount
from organization o
inner join student s on s.organizationid = o.organizationid
group by o.parentunit, o.unit;
To include the parent unit name:
select
(
select unitname
from organization po
where po.parentunit = o.parentunit
and po.unit =0
and po.childunit = 0
) as parentunitname,
min(case when o.childunit = 0 then o.unitname end) as unitname,
count(*) as studentcount
from organization o
inner join student s on s.organizationid = o.organizationid
group by o.parentunit, o.unit;
Or:
select
min(po.unitname) as parentunitname,
min(case when o.childunit = 0 then o.unitname end) as unitname,
count(*) as studentcount
from organization o
inner join student s on s.organizationid = o.organizationid
inner join
(
select parentunit, unitname
from organization
where unit = 0 and childunit = 0
) po on po.parentunit = o.parentunit
group by o.parentunit, o.unit;

Count and where conditions leades to perfomance issues?

I am working on a million data rows table.The table look likes below
Departement year Candidate Spent Saved
Electrical 2013 A 50 50
Electrical 2013 B 25 50
Electrical 2013 C 11 50
Electrical 2013 D 25 0
Electrical 2013 Dt 86 50
Electrical 2014 AA 50 50
Electrical 2014 BB 25 0
Electrical 2014 CH 11 50
Electrical 2014 DG 25 0
Electrical 2014 DH 0 50
Computers 2013 Ax 50 50
Computers 2013 Bc 25 50
Computers 2013 Cx 11 50
Computers 2013 Dx 25 0
Computers 2013 Dx 86 50
I am looking output like below.
Departement year NoOfCandidates NoOfCandidatesWith50$save NoOfCandidatesWith0$save
Electrical 2013 5 4 1
Electrical 2014 5 3 2
Computers 2013 5 4 1
I am using #TEMP tables for every count where conditions and left outer joining at last .So it takes me more time.
Is there any way so i can perform better for above Table .
Thanks in advance.
You want to do this as a single aggregation query. There is no need for temporary tables:
select department, year, count(*) as NumCandidates,
sum(case when saved = 50 then 1 else 0 end) as NumCandidatesWith50Save
sum(case when saved = 0 then 1 else 0 end) as NumCandidatesWith00Save
from table t
group by department, year
order by 1, 2;

SQL How to group a table with special condition and join to another table

i have Table PRICE
CodePrice CodeClient TheZone Tempo W_Begin W_End Price
A_0_49 88989 1 1 0 49 20
A_50_99 60000 1 1 50 99 10
B_0_49 88989 2 1 0 49 30
C_0_49 50000 3 4 0 49 40
Table Ordre
NoID CodeClient Cp Agence TheZone Tempo Weight
01 88989 44 bidon 1 1 12
02 60000 49 toto 2 2 10
03 60000 49 bigoi 1 1 56
04 88989 49 titi 3 3 8
05 50000 44 bidon 1 1 5
How can i show the result like this:
CodePrice TheZone Tempo W_Begin W_End SUm_Weight SUM_Price CountIDOrdre CP Agence
A_0_49 1 1 0 49 17 40 2 44 bidon
A_50_99 1 1 50 99 56 10 1 49 bigoi
B_0_49 2 1 0 49 0 0 0 null null
C_0_49 3 4 0 49 0 0 0 null null
in 1 SQL Syntax (1 Step).
Nowdays i make it in 2 step
SELECT CodePrice
,CodeClient
,TheZone
,Tempo
,W_Begin
,W_End
,Price
FROM PRICE
LEFT JOIN T_TARIF_ZONE ON PRICE.ZONE = T_TARIF_ZONE.NO_ID
LEFT JOIN CLIENT ON PRICE.CodeClient= CLIENT.CODE_CL
WHERE CodeClient= #NO_CLIENT AND TheZone = #ZONE AND UNITE = #UNITE
AND (Tempo IN (SELECT ParsedString From dbo.ParseStringList(#ModLiv)))
ORDER BY MONTANT
after i select the price, now i can group the ordre on each price depends on Weight, zone, and another variable
SELECT count(NoID) as LVId
,sum(Weight)as Tot_Poids
,sum(Price) as Tot_Prix
FROM [Ordre]
WHERE Weight>= #TR_DEB AND Weight<= #TR_FIN AND LE_ZONE = #LE_ZONE AND ENLEV_UNITE = #ENLEV_UNITE
AND DATE_CLOTURE >= #Date_Deb AND DATE_CLOTURE <= #Date_Fin AND STATUT_LV = 2 AND FACTURATION = #FACTURATION
HAVING count([NOID]) > 0