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
Related
Hi I'm trying to find out how frequently a business would change their address. I've got two tables one with trading address and the other with office address. The complicated part is one id will have several sequence numbers. I need to find out the difference between one address's create date and another address create date.
Trading address table
ID
Create_date
Seq_no
Address
1
2002-03-23
1
20 bottle way
1
2002-05-23
2
12 sunset blvd
2
2003-01-14
1
76 moonrise ct
Office address table
ID
Create_date
Seq_no
Address
1
2004-02-13
1
12 paper st
2
2005-03-01
1
30 pencil way
2
2005-04-01
2
25 mouse rd
2
2005-08-01
3
89 glass cct
My result set will be
Difference
NumberOfID's
30 days
1
60 days
1
120 days
1
Other
2
I think I solved it. Steps are
I did an union and created a separate column to find out actual
sequence no for the union set.
Used LEAD function to create a separate column of to bring up the date.
Date difference to find out the actual difference between id's
Case statement to categorize the days and counting the id's
WITH BASE AS (
SELECT ID,SEQ_NO,CREATE_DATE
FROM TradingAddress
UNION ALL
SELECT ID,SEQ_NO,CREATE_DATE
FROM OfficeAddress
),
WORKINGS AS (
SELECT ID,CREATE_DATE,
DENSE_RANK() OVER (PARTITION BY ID ORDER BY CREATE_DATE ASC) AS SNO,
LEAD(CREATE_DATE) OVER (PARTITION BY ID ORDER BY CREATE_DATE) AS REF_DATE,
DATEDIFF(DAY,CREATE_DATE,LEAD(CREATE_DATE) OVER (PARTITION BY ID ORDER BY CREATE_DATE)) AS DATE_DIFFERENCE
FROM BASE
),
WORKINGS_2 AS (
SELECT *,
CASE WHEN DATE_DIFFERENCE BETWEEN 1 AND 30 THEN '1-30 DAYS'
WHEN DATE_DIFFERENCE BETWEEN 31 AND 60 THEN '31-60 DAYS'
WHEN DATE_DIFFERENCE BETWEEN 61 AND 90 THEN '61-90 DAYS'
WHEN DATE_DIFFERENCE BETWEEN 91 AND 120 THEN '91-120 DAYS'ELSE 'MORE THAN 120 DAYS'
END AS DIFFERENCE_DAYS
FROM WORKINGS
WHERE REF_DATE IS NOT NULL
)
SELECT DIFFERENCE_DAYS,COUNT(DIFFERENCE_DAYS) AS NUMBEROFIDS
FROM WORKINGS_2
GROUP BY DIFFERENCE_DAYS
you can do this in this way
SELECT DATEDIFF(day,t1.create_date,t2.create_date) AS 'yourdats', Count (*) as ids FROM test1 t1 join test2 t2 on t1.id = t2.id GROUP BY DATEDIFF(day,t1.create_date,t2.create_date)
I have the following data:
Year score count
2012 20 grade 2000
2005 20 grade 32
2005 40 grade 428
2006 60 grade 731
2006 60 grade 472
...
I would need to know what percentage of occasions when the score is 60 grade does it lead to a good score.
I should assume the word grade appears in the text the word grade (so in this case 60 grade).
My expected output would be the percentage of rows with only 60 grade based on counts.
How can I select this information by looking at values with 60 grade in Score and determine the percentage?
You could try using a condition aggregation
select count(*)
, sum(case when score like '60%' then 1 else 0 end) num_x_60
, (sum(case when score like '60%' then 1 else 0 ) / count(*))*100 perc
from my_table
I recommend using avg() for the percentage:
select avg(case when score like '60%' then 100.0 else 0 end) as percentage
from my_table
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
Here is the code:
SELECT * FROM COMPANY WHERE SALARY > 40000;
4 Mark 25 Rich-Mond 65000.0
5 David 27 Texas 85000.0
6 Kim 22 South-Hall 45000.0
8 Kitos 31 90000.0
SELECT * FROM COMPANY
WHERE AGE < (SELECT AGE FROM COMPANY WHERE SALARY > 40000);
3 Teddy 23 Norway 20000.0
6 Kim 22 South-Hall 45000.0
7 James 24 Houston 10000.0
How does this work when there are multiple row returned from the sub-query? In this example I would expect the last query to produce employees younger than 22 (minimum from the sub-query), apparently it doesn't work that way.
Most databases will raise an error if the subquery does not return exactly one result. SQLite doesn't, but just uses the first returned row (or NULL) (there is an implied LIMIT 1).
The order of SELECT results is not guaranteed without an ORDER BY, so the result will be random.
If you want to use some specific record, you must ensure that you SELECT returns exactly that record, typically using MIN/MAX, or with ORDER BY:
SELECT ...
FROM Company
WHERE Age < (SELECT MIN(Age)
FROM Company
WHERE Salary > 40000);
SELECT ...
FROM Company
WHERE Age < (SELECT Age
FROM Company
WHERE Salary > 40000
ORDER BY Age
LIMIT 1);
It is also possible to use a correlated subquery, which can return a different result for each row in the outer query:
SELECT ...
FROM Company
WHERE Age < (SELECT Age
FROM Company AS C2
WHERE C2.ID = Company.ManagerID);
I have a table of licence applications I want to display the data by category for each financial year.
For my query, there are 2 key columns.
Firstly, there is a fee column and the values within this column determine the type of licence.
Between 0 and 300 is Minor
between 300 and 600 is Standard
between 600 and 2000 is Major
Secondly, there is a date field which is to be used for the financial year.
I would like the results to look like this.
Category | 2013/14 | 2012/13
Minor | 23 | 21
Standard | 10 | 11
Major | 5 | 3
I have this query below, but i cant get it right for the year part.
Would really appreciate any advice people can give me.
select category.gr as [category],
sum(case when ((year(licence.[start_date]) in ('2010'))
and (month(licence.[start_date]) in (4,5,6,7,8,9,10,11,12)))
or ((year(licence.[start_date]) in ('2011'))
and (month(licence.[start_date]) in (1,2,3))) then 1 else 0 end) AS '10/11 Count',
from ( select case
when [fee_INC] between 0 and 350 then 'Minor'
when [fee_INC] between 350 and 600 then 'Standard'
else 'Major' end as gr
from [L_LICENCE_FIN]) as category,
from [L_LICENCE_FIN] as licence
group by category.gr
SELECT
[category],
[2013/14],
[2012/13]
FROM (
SELECT
[category],
STR(YEAR(DATEADD(month,-3,[start_date])),4)
+'/'
+RIGHT(STR(YEAR(DATEADD(month,-3,[start_date]))+1,4),2)
AS [fiscal_year],
COUNT(*) AS [count]
FROM #L_LICENCE_FIN
INNER JOIN (VALUES
( 0, 300, 'Minor'),
(300, 600, 'Standard'),
(600,2000, 'Major')
) categories([fee_min], [fee_max], [category])
ON ([fee] >= [fee_min] AND [fee] < [fee_max])
GROUP BY [category],[start_date]
) p1
PIVOT(SUM([count]) FOR [fiscal_year] IN ([2013/14],[2012/13])) p2