Using a case expression to group by age in SQL - sql

I am currently writing some SQL for a project. I would like to try practicing case expressions, and in this case, practicing grouping records by age.
Here's the table I'm working with: Person
Name | Age
-----------
Mike | 32
Angela | 11
Chris | 65
Nat | 20
Sandra | 45
Shane | 82
I want to use a case expression to group these these people by age. I'd like to divide people into
-18 and younger
-19 to 40
-41 and older
So far, I've been trying to write a case expression like this:
select name, age
from person
order by
(case
when age < 18 //group first
when (age >= 19 and age < 40 //group second
else //group third
end);
Obviously this isn't working. I've been trying to understand case expressions a bit better, can anyone give me some pointers?

Here's what you are trying to achieve.
select name, age
from person order by
case when age < 18 then 0 when age >=19 and age <=40 then 1 else 2 end

We can try using a CASE expression to form the age groups:
SELECT
Name,
Age,
CASE WHEN Age <= 18 THEN 'young'
WHEN Age <= 40 THEN 'middle'
ELSE 'older' END AS age_group
FROM yourTable
ORDER BY
Age;

Try this.
Select AgeGroup, count(distinct *) as
count_names
from(SELECT NAME, CASE WHEN
Age <=
18 THEN 'young (1-18)'
WHEN Age <= 40 THEN 'Middle(19-
40)'
ELSE 'older (40-above)' END as
AgeGroup) group by AgeGroup

Related

How to output a value refer to another value?

I have a table which including Student's name, course_id and score, the different students may have a different course and different score.
And now I need to output the academic standings for each student, here is the rule for the academic standings:
If a student takes only one course(count(course_id)=1), he/she will receive ‘Good’ if the score >= 50, and ‘Referral’ if the score < 50;
If a student takes more than one course (count(course_id)>=2), his/her academic standing would be ‘Probation’ if none of the score >=50, ‘Referral’ if 50% or less of the taken courses are score >=50, and ‘Good’ otherwise.
Table:
Student_name| course_id |score
Shirley Caws 55993 10
Lana Glendenning 56988 81
Michael 54880 80
Michael 54895 71
Sean Turle 56986 32
Sean Turle 56991 48
Sean Turle 56992 20
Damchu Tenzin 56215 40
Damchu Tenzin 56219 90
Blake Croll 57179 30
Blake Croll 57264 20
I have tried for an hour in writing "CASE WHEN" but fail to get the right answer.
SELECT student_name, (CASE WHEN .... THEN ELSE END) AS academic standings FROM table;
Expected results:
Student_name| Academic_standings
Shirley Caws Referral
Lana Glendenning Good
Michael Good
Sean Turle Probation
Damchu Tenzin Referral
Blake Croll Probation
Thanks!
I'd try something like this - count the classes first, then apply your logic:
; with CTE as (
Select StudentName
, Count(distinct CourseID) as TotalClasses
, Count(distinct case when score < 50 then CourseID end) as ClassesUnder50
From MyTable
Group By StudentName
)
Select StudentName
, Case when TotalClasses = 1 and ClassesUnder50 = 0 then 'Good'
when TotalClasses = 1 and ClassesUnder50 = 1 then 'Referral'
when TotalClasses > 1 and ClassesUnder50 = TotalClasses then 'Probation'
when TotalClasses > 1 and ClassesUnder50*1.0/TotalClasses >= 0.5 then 'Referral'
else 'Good' end as Standing
from CTE
You can use aggregation functions and conditional aggregation:
select student_name,
(case when count(*) = 1 and max(score) >= 50 then 'Good'
when count(*) = 1 then 'Referral'
when max(score) < 50 then 'Probation'
when sum(case when score >= 50 then 1 else -1 end) <= 0 then 'Referral'
else 'Good'
end) as academic_standing
from t
group by student_name;

SQL Server: how do I show placeholder rows from a case statement?

If I have a table of data about people's ages such as:
Name | Age
--------+-----------
John | 35
Mike | 45
And I need to group by and output this data into a standard table such as:
Grouper | Count
---------+-------------
Under 50 | 2
Over 50 | 0
I am running a query similar to this (typed up quickly, may not work in real life. Illustrating a situation where I am using a case statement to create groups):
select
case
when Age <= 50 then 'Under 50'
else 'Over 50'
end as 'Grouper',
count(Age) as 'Count'
from
theTable
group by
'Grouper'
I get an answer like this since there are no people over 50 in the table:
Grouper | Count
---------+-------------
Under 50 | 2
How can I force my results to keep every value in the case statement, even if there are no values found for it in the table? I am not able to insert or modify any data or tables, this would be strictly for reporting purposes.
I would phrase this as:
select v.grouper, count(Age) as 'Count'
From (values ('Under 50', 0, 51), ('Over 50', 51, null)) v(grouper, lo, hi) left join
theTable t
on t.age >= v.lo and
(t.age < v.hi or v.hi is null)
Group by grouper;
This generates something like a temporary lookup table with the age ranges and string that you want to include. The important part -- from your perspective -- is the left join. That keeps all the age ranges.
Use UNION, as in:
select
'Under 50' as grouper,
sum(case when age <= 50 then 1 end) as count
from theTable
union
select
'Over 50' as grouper,
sum(case when age > 50 then 1 end) as count
from theTable

How to find rows where the same column has only the same another column

Suppose following table:
Name Age Occupation
Alex 20 Student
Alex 20 Seller
Alex 20 Minister
Liza 19 Student
Liza 20 Volunteer
Liza 21 HR partner
I want to find names which have only (and only) 20 in age column. So from this table I want to get all "Alex" rows and no "Liza" rows at all.
Thanks!
You need to use Group By and Having clause. Try this way
select Name
from table
group by Name
having count(case when Age = 20 then 1 end) = count(*)
count(case when Age = 20 then 1 end) counts only when age = 20 if it is equal to total count then the name has only 20 as age.
Just one another way:
select Name
from table
group by Name
having min(Age) = 20 and max(Age) = 20
One way is using NOT IN():
SELECT Name, Age, Occupation
FROM YourTable
WHERE Age = 20
AND Name NOT IN (SELECT Name FROM YourTable WHERE Age <> 20)

SQL group students by age from date of birth

I have a table "student" that features student's "name" and "DOB".
I would like to group students into the following groups:
a. 10-12
b. 13-14
c. 15-16
d. >= 17
so it would appear
a. paul, peter mary
b. john, william
etc.
How would I go about this?
So far I have:
select case
when age between 10 and 12 then a
when age between 13 and 14 then b
when age between 15 and 16 then c
when age >= 17 then d
from (
SELECT ROUND(DATEDIFF(Cast(CURRENT_TIMESTAMP() as Date),
Cast(birthday as Date)) / 365, 0) as age
FROM db.student
but can't seem to get my head around it.
I am using Management Studio.
Many thanks in advance.
The following query would probably get you the desired results. First, the age is determined. (I added the date format - day - in the DATEDIFF function). Then, the age category is determined.
WITH ages AS
(
SELECT
name,
ROUND(DATEDIFF(day, Cast(CURRENT_TIMESTAMP() as Date), Cast(birthday as Date)) / 365, 0) as age
FROM db.student
)
SELECT
name,
case
when age between 10 and 12 then a
when age between 13 and 14 then b
when age between 15 and 16 then c
when age >= 17 then d
end as age_category
FROM ages
ORDER BY name;

SQL Group By Help Required

I have a table named People in the following format:
Date | Name.
When I count the people by Grouping By Name with
Select Date, Name, count(*)
From People
Group By Date, Name;
Will give the following
Date Name count(*)
10 Peter 25
10 John 30
10 Mark 25
11 Peter 15
11 John 10
11 Mark 5
But I would like the following result:
Date Peter John Mark
10 25 30 25
11 15 10 5
Is this possible? This is a simple example of a more complicated database. If someone helps me in solving this problem I will use the concept to implement it in my table
Thanks!
Select Date
, count(case when Name = 'Peter' then 1 else null end)
, count(case when Name = 'John' then 1 else null end)
, count(case when Name = 'Mark' then 1 else null end)
From People
Group By Date;
another option different from turbanoff's if, for some reason, you find yourself in a situation that you cant apply a group by:
Select distinct(P.Date),
(select count(*) from People where date=p.date and name='Peter') as Peter,
(select count(*) from People where date=p.date and name='John') as John,
(select count(*) from People where date=p.date and name='Mark') as Mark
From People P