Learning SQL, trying to figure out how to get a gender count - sql

I'm learning SQL and one of the questions that got thrown at me in my solo study suddenly is to write a script in order to count how many of each gender is in the client table,
Table CLIENT:
ClientID `First Name` `Last Name` Gender ID `Birth Date`
1 Sally Fields 1 03/05/2000
2 Hannah Montana 1 02/20/1989
3 Bart Simpson 2 02/03/1966
4 Michael Jordan 2 05/02/1970
5 Glennon Doyle 1 NULL
6 Lulu Jenkins 1 09/30/2001
Table GENDER:
ID `Gender Description`
1 Female
2 Male
I'm still very new to this so I'm stumped... the furthest I've gotten is:
SELECT
u.GenderID Gender,
COUNT(u.GenderID)
I'm not sure of where to go from there... the stuff I'm studying went from 1-100 really fast and I'm totally lost lol. Any guidance would be much appreciated!

Assuming you want to return the gender name and a count of each, simply join your two tables and aggregate, grouping by the gender description and counting the rows that belong to each grouping:
select g.`Gender Description`, Count(*) GenderCount
from client c
join gender g on g.id = c.GenderId
group by g.`Gender Description`;
Note the use of short meaningful aliases makes the query more compact and easy to read at a glance.

with GenderTable AS
(
SELECT
CASE
WHEN 'Gender ID'=1 Then 'Female'
Else 'Male'
END AS gender
FROM CLIENT
)
SELECT count(gender), gender
FROM GenderTable
GROUP BY gender
;
You can try this too using the Common Table Expression

Related

SQL Window Function to get addresses with more than 1 unique last name present (Snowflake)

I have a Snowflake table which includes addresses, state, first names and last names.
I would like to get a query that shows me only the addresses where more than 1 individual with a different last name is present.
So for example, assume that I have
address | fname | lname |State
10 lake road| John | Smith |FL
10 lake road| Julie | Gallagher|FL
3 gator cove| Jack | Hoyt |FL
3 gator cove| Debra | Hoyt |FL
I would like the query to return only 1 row in that example: 10 lake road. Because it's the only house where there is more than 1 unique last name present.
I am currently using
SELECT distinct a.address, a.fname, a.lname, a.state
FROM clients_addresses a
WHERE a.state = 'FL'
qualify count(1) over( partition by a.lname) > 1
order by a.address
However, this is just returning the addresses where there is more than 1 person, it doesn't care if the last name is repeated. That's what I'm trying to avoid.
I can't quite understand where the query is going wrong. Snowflake doesn't like using any distinct keyword after the initial select, and even if I use it, it only returns 1 occurrence of each address, but it's still just addresses with more than 1 person, even if there was only 1 last name in the address.
It doesn't need to involve the keyword "qualify", I know Snowflake also accepts other things such as subselects that might help with this problem.
I would like the query to return only 1 row in that example: 10 lake road.
This sounds like aggregation:
SELECT a.address, count(*)
FROM clients_addresses a
WHERE a.state = 'FL'
GROUP BY a.address
HAVING COUNT(DISTINCT a.lname) > 1;
If you want the original rows (which is not what your question asks for), you can use:
SELECT a.*
FROM clients_addresses a
WHERE a.state = 'FL'
QUALITY COUNT(DISTINCT a.lname) OVER (PARTITION BY a.address) > 1;

Count SQL Query Assistance

I am learning how to use SQL and can't seem to work out how to do this kind of query.
The data set has a list of male and female school results which are allocated a score.
LearningArea YearLevel AchievementResult Gender NumericalScore
ENGLISH 1 A M 1
ENGLISH 1 C M 3
ENGLISH 1 C F 3
ENGLISH 1 B F 2
I am trying to analyse the data to show the total score for males and the total score for females without having to do 2 queries.
I have tried myself and looked around but I have only been able to do it with 2 queries.
SELECT Count(Score) AS Male
FROM Data
WHERE Gender = "M"
&
SELECT Count(Score) AS Female
FROM Data
WHERE Gender = "F"
All I'm looking for is anyone that knows of a way to make this one query.
Thanks in Advance
SELECT Gender,Count(*) AS Number
FROM Data
GROUP BY Gender
Based upon the text of your question, you may want SUM instead of COUNT but I'm sure you can work it out from here.
you can use case:
SELECT
COUNT(CASE WHEN Gender = "M" then 1 ELSE NULL END) AS "Male",
COUNT(CASE WHEN Gender = "F" then 1 ELSE NULL END) AS "Female"
FROM Data

Selecting count by row combinations

I'm strugling with what on the first sight appeared to be simple SQL query :)
So I have following table which has three columns: PlayerId, Gender, Result (all of type integer).
What I'm trying to do, is to select distinct players of gender 2 (male) with number of each results.
There are about 50 possible results, so new table should have 51 columns:
|PlayerId | 1 | 2 | 3 | ... | 50 |
So I would like to see how many times each individual male (gender 2) player got specific result.
*** In case question is still not entirely clear to you: After each game I insert a row with a player ID, gender and result (from 1 - 50) player achieved in that game. Now I'd like to see how many times each player achieved specfic results.
If there are 50 results and you want them in columns, then you are talking about a pivot. I tend to do these with conditional aggregation:
select player,
sum(case when result = 0 then 1 else 0 end) as result_00,
sum(case when result = 1 then 1 else 0 end) as result_01,
. . .
sum(case when result = 50 then 1 else 0 end) as result_50
from t
group by player;
You can choose a particular gender if you like, with where gender = 2. But why not calculate all at the same time?
try
select player, result, count(*)
from your_table
where Gender = 2
group by player, result;
select PleyerId from tablename where result = 'specific result you want' and gender = 2 group by PleyerId
The easiest way is to use pivoting:
;with cte as(Select * from t
Where gender = 2)
Select * from cte
Pivot(count(gender) for result in([1],[2],[3],....,[50]))p
Fiddle http://sqlfiddle.com/#!3/8dad5/3
One note: keeping gender in scores table is a bad idea. Better make a separate table for players and keep gender there.

write a query to identify discrepancy

I have a table with Student ID's and Student Names. There has been issues with assigning unique Student Id's to students and Hence I want to find the duplicates
Here is the sample Table:
Student ID Student Name
1 Jack
1 John
1 Bill
2 Amanda
2 Molly
3 Ron
4 Matt
5 James
6 Kathy
6 Will
Here I want a third column "Duplicate_Count" to display count of duplicate records.
For e.g. "Duplicate_Count" would display "3" for Student ID = 1 and so on. How can I do this?
Thanks in advance
Select StudentId, Count(*) DupCount
From Table
Group By StudentId
Having Count(*) > 1
Order By Count(*) desc,
Select
aa.StudentId, aa.StudentName, bb.DupCount
from
Table as aa
join
(
Select StudentId, Count(*) as DupCount from Table group by StudentId
) as bb
on aa.StudentId = bb.StudentId
The virtual table gives the count for each StudentId, this is joined back to the original table to add the count to each student record.
If you want to add a column to the table to hold dupcount, this query can be used in an update statement to update that column in the table
This should work:
update mytable
set duplicate_count = (select count(*) from mytable t where t.id = mytable.id)
UPDATE:
As mentioned by #HansUp, adding a new column with the duplicate count probably doesn't make sense, but that really depends on what the OP originally thought of using it for. I'm leaving the answer in case it is of help for someone else.

SQL Server, how to join a table in a "rotated" format (returning columns instead of rows)?

Sorry for the lame title, my descriptive skills are poor today.
In a nutshell, I have a query similar to the following:
SELECT P.LAST_NAME, P.FIRST_NAME, D.DEMO_GROUP
FROM PERSON P
JOIN PERSON_DEMOGRAPHIC PD ON PD.PERSON_ID = P.PERSON_ID
JOIN DEMOGRAPHIC D ON D.DEMOGRAPHIC_ID = PD.DEMOGRAPHIC_ID
This returns output like this:
LAST_NAME FIRST_NAME DEMO_GROUP
---------------------------------------------
Johnson Bob Male
Smith Jane Female
Smith Jane Teacher
Beeblebrox Zaphod Male
Beeblebrox Zaphod Alien
Beeblebrox Zaphid Politician
I would prefer the output be similar to the following:
LAST_NAME FIRST_NAME Male Female Teacher Alien Politician
---------------------------------------------------------------------------------------------------------
Johnson Bob 1 0 0 0 0
Smith Jane 0 1 1 0 0
Beeblebrox Zaphod 1 0 0 1 1
The number of rows in the DEMOGRAPHIC table varies, so I can't say with certainty how many columns I need. The query needs to be flexible.
Yes, it would be trivial to do this in code. But this query is one piece of a complicated set of stored procedures, views, and reporting services, many of which are outside my sphere of influence. I need to produce this output inside the database to avoid breaking the system. Any ideas?
This is MS SQL Server 2005, by the way.
Thanks.
You can use the PIVOT function. HereĀ“s a piece of code. This function needs the columns in advance, but if you do not know the number of columns, you should make a dynamic sql query. Take a look at this answer.
SELECT LAST_NAME, FIRST_NAME, [Male], [Female], [Alien], [Politician], [Teacher]
FROM
(SELECT LAST_NAME, FIRST_NAME, DEMO_GROUP
FROM Person) p
PIVOT
(
COUNT (DEMO_GROUP)
FOR DEMO_GROUP IN
( [Male], [Female], [Alien], [Politician], [Teacher] )
) AS pvt
ORDER BY LAST_NAME
Assuming the list of Demo_Group to be returned is known ahead of time, you can do the following:
SELECT P.LAST_NAME, P.FIRST_NAME
, Sum( Case When Demo_Group = 'Male' Then 1 Else 0 End ) As Male
, Sum( Case When Demo_Group = 'Female' Then 1 Else 0 End ) As Female
, Sum( Case When Demo_Group = 'Teacher' Then 1 Else 0 End ) As Teacher
, Sum( Case When Demo_Group = 'Alien' Then 1 Else 0 End ) As Alien
FROM PERSON P
JOIN PERSON_DEMOGRAPHIC PD
ON PD.PERSON_ID = P.PERSON_ID
JOIN DEMOGRAPHIC D
ON D.DEMOGRAPHIC_ID = PD.DEMOGRAPHIC_ID
Group By P.LAST_NAME, P.FIRST_NAME
If the list of Demo_Group values is not known, meaning you want the columns to be dynamically generated, then the only way to do that is using some fugly dynamic SQL. This is not what SQL was designed to do and instead should be done in a middle-tier or reporting tool.