Group By returning 1st column values twice - sql

I have data that looks like:
ACC311 Female 3
ACC311 Female 1
ACC311 Female 4
ACC311 Male 4
ACC501 Male 4
ACC501 Male 4
ACC501 Male 4
ACC501 Male 4
.
.
.
Now I am using following query to get results
Select distinct coursecode, gender, Count(CQ) as CQ from Table1
group by Coursecode, gender
order by Coursecode
It is returning results as following, which is obviously not a correct
way as per required output (see below)
CourseCode Gender CQ
ACC311 Male 45
ACC311 Female 22
ACC501 Female 228
ACC501 Male 485
Where as I need to get following:
CourseCode Total Male Female CQ
ACC311 67 45 22 11
ACC501 713 485 228 111

Your query returns rows "twice" because you group by Coursecode, gender. DISTINCT won't help either.
The easiest way to get desired result is to use conditional aggregation:
SELECT Coursecode,
Count(CQ) AS CQ,
COUNT(gender) AS Total,
COUNT(CASE WHEN gender = 'Male' THEN 1 END) AS Male,
COUNT(CASE WHEN gender = 'Female' THEN 1 END) AS Female
FROM Table1
GROUP BY Coursecode

Related

Count occurrences with exclude criteria

I have a Table
City ID
Austin 123
Austin 123
Austin 123
Austin 145
Austin 145
Chicago 12
Chicago 12
Houston 24
Houston 45
Houston 45
Now I want to count the occurrences of all Citis with different ids so since Chicago has only one id (=12) I am not interested in Chicago and it should not appear in the resultset that should looks like this:
city Id Occurrences
Austin 123 3
Austin 145 2
Houston 34 1
Houston 45 2
I am able to get myself an overview with
select city, Id from Table
group by city, Id
But I am not sure how to only select the once having different ids and to count them.
Could anyone help me out here?
You can use window functions and aggregation:
select city, id, occurences
from (
select city, id, count(*) occurences, count(*) over(partition by city) cnt_city
from mytable
group by city, id
) t
where cnt_city > 1

HIVE Get male and female count who opted for any course

I have two tables, students and training. Student and Training tables are as below.
Student
ID name age sex salary
1213 lavanya 18 Female 8000
1208 reshma 19 Female 14000
1207 bhavya 20 Female 15000
1212 Arshad 28 Male 20000
1209 kranthi 22 Male 22000
1210 Satish 24 Male 25000
1211 Krishna 25 Male 26000
1203 khaleel 34 Male 30000
1204 prasant 30 Male 31000
1206 laxmi 25 Female 35000
1205 kiran 20 Male 40000
1201 gopal 45 Male 50000
1202 manisha 40 Female 51000
Training
1 1201 csharp
2 1205 c
3 1201 c
4 1202 java
5 1205 java
6 1203 shell
7 1204 hadoop
8 1201 hadoop
Now I want count of males and females who have joined any course.
I tried below query-
hive> select s.sex, count(*) from student join training t on s.id=t.sid group by s.sex;
But this query is giving output as Female 2 Male 4
Though expected outcome should be Female 1 Male 2
Please note this is a sample and short form of data being used.
This looks like your query, but - returns the result you mentioned (1 female, 2 male). If possible, post your own SQL*Plus copy/paste session (take my example) so that we'd see what you exactly did).
SQL> with student (id, name, sex) as
2 (select 1, 'alex', 'm' from dual union
3 select 2, 'rita', 'f' from dual union
4 select 3, 'max', 'm' from dual union
5 select 4, 'steve', 'm' from dual
6 ),
7 training (id, sid, course) as
8 (select 1, 2, 'java' from dual union
9 select 2, 3, 'c' from dual union
10 select 3, 1, 'java' from dual
11 )
12 select s.sex, count(*)
13 from student s join training t on t.sid = s.id
14 group by s.sex;
S COUNT(*)
- ----------
m 2
f 1
I try in MySQL and in Oracle, and this query is OK.
SELECT S.sex, count(*)
FROM student s
INNER JOIN training T on S.id = T.sid
GROUP BY S.sex;
RESULT, female = 1, male = 2
If the only thing you want is a simple count by gender, why not use
select sex, count(*)
from student
group by sex
order by sex
Use exists:
select s.sex, count(*)
from students s
where exists (select 1 from training t where t.sid = s.id);
The problem with join is that it counts each student based on the number of trainings they are in.
Here i had written a code taking your data:-
SELECT
final.ct_sex as sex,count(*) as num
FROM
(SELECT tb.sex as ct_sex FROM newschema.mytable AS tb JOIN (SELECT tr.ID,GROUP_CONCAT(tr.skill) as skills FROM newschema.train AS tr GROUP BY tr.ID) AS tp ON tb.ID = tp.ID) as final
group by
final.ct_sex
Not sure why join fails here, Below subquery is giving correct output though.
select sex, count(*) from salary where salary.id in (select sid from training) group by salary.sex;

Oracle SQL Query Tuning for output

I have an output such as below
select City, Gender, count(*) from tablename group by City, Gender ;
City Gender count(*)
Chennai Male 640000
Chennai Female 623000
Blore Male 500000
Blore Female 600000
Pune Male 700000
Pune Female 700000
But I am looking for getting the same output as like below
City Male Female
Chennai 640000 623000
Blore 500000 600000
Pune 700000 700000
Appreciate your help.
Thanks
You need conditional sum for this
select
City,
sum(case when Gender = 'Male' then 1 else 0 end) as Male,
sum(case when Gender = 'Female' then 1 else 0 end) as Female
from tablename group by City
Here is short code
select city,sum(male),sum(female) from tablename group by city;

have trouble when table.field_name is needed in two columns based on different values

I have a person table that has a sex field and a few other fields. Looks like this
firstname lastname sex birthday
--------- -------- --- ---------
john doe 0 1960-01-25
jane doe 1 1990-02-01
john smith 0 1995-03-15
mary smith 1 1990-01-16
so sex = 0 means male sex = 1 means female.
I'd like to see this as a result assuming the current_date as 2014-02-04
Age Female Male
--- ------ ----
18 0 1
24 2 0
54 0 1
I have this
SELECT count(*) AS Female,
cast(DATEDIFF(CURRENT_DATE,person.birthday)/(365.256366) AS SIGNED) AS Age
FROM person
WHERE person.sex=1
GROUP BY Age
which gives me the above result without the Male col. I can do a similar one for Male and Age but no Female. How do merge the two to get all three columns?
You can do that as a conditional SUM:
SELECT SUM(CASE WHEN person.sex=1 THEN 1 ELSE 0 END) AS Female,
SUM(CASE WHEN person.sex=0 THEN 1 ELSE 0 END) AS Male,
cast(DATEDIFF(CURRENT_DATE,person.birthday)/(365.256366) AS SIGNED) AS Age
FROM person
GROUP BY Age
BTW your "age" calculation will be close but will not be right when you're on someone's exact birthday day.

SQL script to change the structure of the table

I am working on a SQL database (Microsoft SQL Server 2008)
I have a table like this
Country Gender Number
---------+---------------+-----------+
Russia Male 50000
Russia Female 40000
Russia Unknown 30000
India Male 45678
India Female 21354
China Male 37878
China Female 45686
China Unknown 24534
France Male 45378
France Female 49783
Is there an sql select script that can return a table like this:
Country Male Female Unknown
---------+---------------+-----------+-----------------+
Russia 50000 40000 30000
India 45678 21354 0
China 37878 45686 24534
France 45378 49783 0
Please note that some countries do not have "Unkown" data so in this case it should be 0.
I tried a couple of things but I did not get any close results. Thanks for any help.
You can use pivot operator for such kind of queries:
select Country,
IsNull([Male], 0) Male,
IsNull([Female], 0) Female,
IsNull([Unknown], 0) Unknown
from TableName t
pivot (sum(Number) for Gender in ([Male], [Female], [Unknown])) p
or ... pivot max(Number) for ... if you know that (Country, Gender) combination is unique in original data.
you can also use this query
select
T.Country,
max(case when T.Gender = 'Male' then T.Number else 0 end) as Male,
max(case when T.Gender = 'Female' then T.Number else 0 end) as Female,
max(case when T.Gender = 'Unknown' then T.Number else 0 end) as Unknown
from Table1 as T
group by T.Country
sql fiddle demo