count(*) based on the gender condition - sql

I have the following table in oracle10g.
state gender avg_sal status
NC M 5200 Single
OH F 3800 Married
AR M 8800 Married
AR F 6200 Single
TN M 4200 Single
NC F 4500 Single
I am trying to form the following report based on some condition. The report should look like the one below. I tried the below query but count(*) is not working as expected
state gender no.of males no.of females avg_sal_men avg_sal_women
NC M 10 0 5200 0
OH F 0 5 0 3800
AR M 16 0 8800 0
AR F 0 12 0 6200
TN M 22 0 4200 0
NC F 0 8 0 4500
I tried the following query but I am not able to count based onthe no.of males and no.of females..
select State, "NO_OF MALES", "$AVG_sal", "NO_OF_FEMALES", "$AVG_SAL_FEMALE"
from(
select State,
to_char(SUM((CASE WHEN gender = 'M' THEN average_price ELSE 0 END)),'$999,999,999') as "$Avg_sal_men,
to_char(SUM((CASE WHEN gender = 'F' THEN average_price ELSE 0 END)), '$999,999,999') as "$Avg_sal_women,
(select count (*) from table where gender='M')"NO_OF MALES",
(select count (*) from table where gender='F')"NO_OF_FEMALES"
from table group by State order by state);

You can use case as an expression (which you already know...). And the subquery is unnecessary.
select State
, sum(case gender when 'M' then 1 else 0 end) as "no.of males"
, sum(case gender when 'F' then 1 else 0 end) as "no.of females"
, to_char(
SUM(
(
CASE
WHEN gender = 'M' THEN average_price
ELSE 0
END
)
)
, '$999,999,999'
) as "Avg_sal_men",
to_char(SUM((CASE WHEN gender = 'F' THEN average_price ELSE 0 END))
,'$999,999,999'
) as "Avg_sal_women"
from table
group by State;

You are Conting by this sub-query select count (*) from table where gender='M' which always count the total number of male in your whole table....and you are doing same for counting female...
So you Can Try like this...
select State, "NO_OF MALES", "$AVG_sal", "NO_OF_FEMALES", "$AVG_SAL_FEMALE"
from(
select State,
to_char(SUM((CASE WHEN gender = 'M' THEN average_price ELSE 0 END)),'$999,999,999') as "$Avg_sal_men",
to_char(SUM((CASE WHEN gender = 'F' THEN average_price ELSE 0 END)), '$999,999,999') as "$Avg_sal_women,
Sum(Case when gender='M' then 1 else 0 end) "NO_OF MALES",
Sum(Case when gender='F' then 1 else 0 end) "NO_OF_FEMALES"
from table group by State order by state);

Try the following.
select state
,sum(case when gender = 'M' then 1 else 0 end) as nof_males
,sum(case when gender = 'F' then 1 else 0 end) as nof_females
,avg(case when gender = 'M' then average_price end) as avg_sal_male
,avg(case when gender = 'F' then average_price end) as avg_sal_female
from table
group
by state;
..add formatting as required.

Related

How to use Group By for Range in PostgreSQL?

I have one table like below at AWS Timeseries:
tracking_id
measure_value::varchar
measure_value::bigint
measure_name
269
-
48
age
269
Male
-
gender
I want to filter it to genders and age range like:
age_range
male_count
female_count
0-12
15
12
13-17
25
17
I already have a query that:
WITH
genderTable AS (SELECT device_identifier, tracking_id, measure_value::varchar as gender FROM "comp_41"."Visqa18f" WHERE device_identifier='visdemo3' AND measure_name='gender' AND tracking_id IS NOT NULL AND time BETWEEN '2021-03-01 10:30:00' AND '2021-03-01 10:56:00' ORDER BY tracking_id),
ageTable AS (SELECT device_identifier, tracking_id, measure_value::bigint as age FROM "comp_41"."Visqa18f" WHERE device_identifier='visdemo3' AND measure_name='age' AND tracking_id IS NOT NULL
AND time BETWEEN '2021-03-01 10:30:00' AND '2021-03-01 10:56:00' ORDER BY tracking_id)
SELECT
SUM(CASE WHEN age > 0 AND age <= 12 AND gender = 'Male' THEN 1 ELSE 0 END) AS "0-12-M",
SUM(CASE WHEN age >= 13 AND age <= 17 AND gender = 'Male' THEN 1 ELSE 0 END) AS "13-17-M",
SUM(CASE WHEN age >= 18 AND age <= 24 AND gender = 'Male' THEN 1 ELSE 0 END) AS "18-24-M",
SUM(CASE WHEN age >= 25 AND age <= 34 AND gender = 'Male' THEN 1 ELSE 0 END) AS "25-34-M",
SUM(CASE WHEN age >= 35 AND age <= 44 AND gender = 'Male' THEN 1 ELSE 0 END) AS "35-44-M",
SUM(CASE WHEN age >= 45 AND age <= 54 AND gender = 'Male' THEN 1 ELSE 0 END) AS "45-54-M",
SUM(CASE WHEN age >= 55 AND gender = 'Male' THEN 1 ELSE 0 END) AS "54-M",
SUM(CASE WHEN age > 0 AND age <= 12 AND gender = 'Female' THEN 1 ELSE 0 END) AS "0-12-F",
SUM(CASE WHEN age >= 13 AND age <= 17 AND gender = 'Female' THEN 1 ELSE 0 END) AS "13-17-F",
SUM(CASE WHEN age >= 18 AND age <= 24 AND gender = 'Female' THEN 1 ELSE 0 END) AS "18-24-F",
SUM(CASE WHEN age >= 25 AND age <= 34 AND gender = 'Female' THEN 1 ELSE 0 END) AS "25-34-F",
SUM(CASE WHEN age >= 35 AND age <= 44 AND gender = 'Female' THEN 1 ELSE 0 END) AS "35-44-F",
SUM(CASE WHEN age >= 45 AND age <= 54 AND gender = 'Female' THEN 1 ELSE 0 END) AS "45-54-F",
SUM(CASE WHEN age >= 55 AND gender = 'Female' THEN 1 ELSE 0 END) AS "54-F"
FROM ageTable, genderTable WHERE ageTable.tracking_id = genderTable.tracking_id
I want to do it with shorter and better optimized query and decided to do it with GROUP BY for age range
How can I use GROUP BY for filter on AGE RANGE?
This should do it:
demo:db<>fiddle
SELECT
CASE
WHEN age BETWEEN 0 and 12 THEN '0 - 12'
WHEN age BETWEEN 13 and 17 THEN '13 - 17'
...
END as age_range,
COUNT(*) FILTER (WHERE gender = 'Male') as male_count,
COUNT(*) FILTER (WHERE gender = 'Female') as female_count
FROM (
SELECT
tracking_id,
MAX(measure_value_gender) as gender,
MAX(measure_value_age) as age
FROM mytable
GROUP BY tracking_id
) s
GROUP BY age_range
If you don't want to use the FILTER clause, you can, of course, use your SUM(CASE WHEN gender = 'Male' THEN 1 ELSE 0 END) construct as well.

Trouble ordering GROUP BY, ORDER BY AND JOIN

i'm having trouble ordering a query.
I have this table (AttendanceLog);
ClassID | StudentPin | Status
69 1 YES
8 2 NO
10 2 NO
17 3 NO
43 5 YES
58 6 YES
and this table (Students):
STUDENTPIN | FNAME | LNAME | INTERNATIONAL
1 X X NO
2 X X YES
3 X X NO
4 X X YES
I want to find out the which INTERNATIONAL students (Fname, Lname and StudentPIN) have missed 10 or more classes (attendancelog status being no).
Currently I have this (below) which tells me the studentPIN and the number of classes attended and no attended by each student, however I am unable to join the two tables together.
SELECT
ATTENDANCELOG.studentpin,
SUM(CASE WHEN status = 'YES' THEN 1 ELSE 0 END) AS number_of_yes,
SUM(CASE WHEN status = 'NO' THEN 1 ELSE 0 END) AS number_of_no
FROM attendancelog
GROUP BY ATTENDANCELOG.studentpin
ORDER BY ATTENDANCELOG.studentpin
Thanks!
you could use a join
SELECT
ATTENDANCELOG.studentpin,
Students.FNAME,
Students.LNAME,
SUM(CASE WHEN status = 'YES' THEN 1 ELSE 0 END) AS number_of_yes,
SUM(CASE WHEN status = 'NO' THEN 1 ELSE 0 END) AS number_of_no
FROM attendancelog
INNER JOIN Students ON Students.STUDENTPIN = attendancelog.StudentPin
and INTERNATIONAL='YES'
GROUP BY ATTENDANCELOG.studentpin, Students.FNAME, Students.LNAME
ORDER BY ATTENDANCELOG.studentpin
Join on student pin, put your international = 'YES' filter in the where clause, and filter for more than 10 misses in a having clause. You can also shorten the case expressions a little:
select a.studentpin
, s.fname, s.lname, s.international
, count(case a.status when 'YES' then 1 end) as attended
, count(case a.status when 'NO' then 1 end) as missed
from attendancelog a
join students s on s.studentpin = a.studentpin
where international = 'YES'
group by s.fname, s.lname, s.international, a.studentpin
having count(case a.status when 'NO' then 1 end) > 10
order by s.fname, s.lname, a.studentpin;

Getting Total Number of Fields from SQL Table and Plot to Chart Using VB.Net

I have table as shown below:
Scholar
ID Gender DateGranted
1 M 1/1/2014
2 F 1/2/2013
3 M 12/25/2015
4 M 3/31/2016
5 F 5/15/2015
so on. . . .
I would like to get this number of male and female (per year) and plot it on Chart.
MALE FEMALE
3 2
What I have done:
(1) SQL Query:
SELECT(case when s.Gender = 'M' then Count(s.gender) else 0 end) as [MALE],
(case when s.Gender = 'F' then Count(s.gender) else 0 end) as [FEMALE] FROM ScholarshipGrants s
WHERE s.DateGranted >= '1/1/2013' AND s.DateGranted
(2) Chart Code
With chart
.Series(0).Points.Clear()
.Series(1).Points.Clear()
.Series(0).Points.DataBind(b, "YEAR", "MALE", "Label=MALE")
.Series(1).Points.DataBind(b, "YEAR", "FEMALE", "Label=FEMALE")
.Series(0).Color = Color.Blue
.Series(1).Color = Color.HotPink
'.Series(0).ChartType = SeriesChartType.Bar
ZeroDataPoint(.Series(1))
.Update()
End With
Result:
Male are not counted
try change your query script:
SELECT SUM(case when s.Gender = 'M' then 1 else 0 end) as [MALE],
SUM(case when s.Gender = 'F' then 1 else 0 end) as [FEMALE]
FROM ScholarshipGrants s
WHERE s.DateGranted >= '1/1/2013' AND s.DateGranted
Use below query :-
SELECT
COUNT (case when s.Gender = 'M' then 1 else NULL end) as [MALE],
COUNT (case when s.Gender = 'F' then 1 else NULL end) as [FEMALE]
FROM ScholarshipGrants s
WHERE s.DateGranted >= '1/1/2013'

How to have condition inside count SQL?

I already tried this code:
SELECT Count(Gender) As MaleCount, Count(Gender) As FemaleCount
FROM [Session4].[dbo].[Survey]
Where Gender = 'M' or Gender = 'F'
I can't get the accurate data when counting with two different conditions in one query.
Pictures below:
This is the result.
This is the original data
SELECT TOP (1000) [Departure]
,[Arrival]
,[Age]
,[Gender]
,[CabinType]
,[Q1]
,[Q2]
,[Q3]
,[Q4]
FROM [Session4].[DBO].[Survey]
count explain :
COUNT(*) counts all rows
COUNT(column) counts non-null value
COUNT(distinct column) counts distinct non-null value
COUNT(1) is the same as COUNT(*)
Use case/when + sum :
SELECT
sum(case when Gender = 'M' then 1 else 0 end ) As MaleCount,
sum(case when Gender = 'F' then 1 else 0 end ) As FemaleCount
FROM [Session4].[dbo].[Survey]
will produce somethings like this :
MaleCount | FemaleCount
1000 | 1255
Another way is using simple goup by
SELECT
Gender,
Count(*)
FROM [Session4].[dbo].[Survey]
GROUP BY
Gender
will produce :
Gender | Count
M | 1000
F | 1255
Try this out:
SELECT sum(case when Gender = 'M' then 1 else 0 end) As MaleCount,
sum(case when Gender = 'F' then 1 else 0 end) As FemaleCount
FROM [Session4].[dbo].[Survey]
Let me know in case of any doubts.

Use of AVG function to determine percentages in a SQL query

I want to know what percentage of records have a given value, where percentage is defined as the number of records that match the value divided by the total number of records. i.e. if there are 100 records, of which 10 have a null value for student_id and 20 have a value of 999999, then the percentage_999999 should be 20%. Can I use the AVG function to determine this?
Option 1:
SELECT year, college_name,
sum(case when student_id IN ('999999999') then 1 else 0 end) as count_id_999999999,
count_id_999999999/total_id as percent_id_999999999,
sum(case when student_id IS NULL then 1 else 0 end) as count_id_NULL,
count_id_NULL/total_id as percent_id_NULL
count(*) as total_id
FROM enrolment_data ed
GROUP BY year, college_name
ORDER BY year, college_name;
Option 2:
SELECT year, college_name,
sum(case when student_id IN ('999999999') then 1 else 0 end) as count_id_999999999,
avg(case when student_id IN ('999999999') then 1.0 else 0 end) as percent_id_999999999,
sum(case when student_id IS NULL then 1 else 0 end) as count_id_NULL,
avg(case when student_id IS NULL then 1.0 else 0 end) as percent_id_NULL
count(*) as total_id
FROM enrolment_data ed
GROUP BY year, college_name
ORDER BY year, college_name;
I created a similar table with 100 records, 20 999999999s, 10 nulls, and 70 1s. This worked for me on SQL Server:
select count(*), StudentID
from ScratchTbl
group by StudentID;
(No column name) StudentID
10 NULL
70 1
20 999999999
select avg(case when StudentID = '999999999' then 1.0 else 0.0 end) as 'pct_9s',
sum(case when StudentID = '999999999' then 1 else 0 end) as 'count_9s',
avg(case when StudentID is null then 1.0 else 0.0 end) as 'pct_null',
sum(case when StudentID is null then 1 else 0 end) as 'count_null'
from ScratchTbl
pct_9s count_9s pct_null count_null
0.200000 20 0.100000 10
I have a feeling that your use of the group by clause could be creating problems for you, perhaps select a specific year/college using the where clause (and get rid of the group by line) and see if you get the results you expect.