Select sport results ordering by medals - sql

I have a table:
sport country place
ski swe 1
ski nor 2
ski rus 3
luge swe 1
luge usa 2
luge ger 3
bob nor 1
bob rus 2
bob ger 3
where place is 1 for gold, 2 for silver, 3 for bronze
Now the normal displying scenario is a list of countries, first max gold, then silver then bronze. for that exampe it would be:
swe g:2 s:0 b:0 sum:2
rus g:0 s:1 b:1 sum:2
usa g:0 s:1 b:0 sum:1
nor g:0 s:0 b:2 sum:2
what would be SQL query to get list of countries ordering by that way?
regards

select
country,
sum(case when place = 1 then 1 else 0 end) as gold,
sum(case when place = 2 then 1 else 0 end) as silver,
sum(case when place = 3 then 1 else 0 end) as bronce,
count(*) as allmedals
from tab
group by country
For ordering the result you might do
order by sum(4 - place) desc -- weighted medals

using multiple ordering is a key: here is query. Thanks to user:dnoeth
select
country,
sum(case when place = 1 then 1 else 0 end) as gold,
sum(case when place = 2 then 1 else 0 end) as silver,
sum(case when place = 3 then 1 else 0 end) as bronce,
count(*) as allmedals
from tab
group by country ORDER BY gold DESC, silver DESC, bronce DESC

Related

SQL: SUM OR COUNT with CASE WHEN condition in multiple criteria

Course name
Section number
Course type
MATH 101
1
In person
MATH 101
2
In person
MATH 101
3
Online
MATH 101
4
In person
SOC 101
1
In person
SOC 101
2
In person
SOC 101
3
In person
ENGL 201
1
In person
ENGL 201
2
Online
ENGL 201
3
Online
ENGL 201
4
In person
PHY 101
1
Online
PHY 101
2
Online
From this table, I'd like to count Courses with only an 'In person' course, an 'Online' course, and both course types.
The query I tried is below.
SELECT
SUM(CASE WHEN coursetype = 'Inperson' AND coursetype = 'Online' THEN 1 ELSE 0 END) AS bothtype,
SUM(CASE WHEN coursetype = 'Online' THEN 1 ELSE 0 END) AS Onlineonly,
SUM(CASE WHEN coursetype = 'Inperson' THEN 1 ELSE 0 END) AS Onlineonly
From Course
The result what I expected is
bothtpye
Onlineonly
Inpersononly
2
1
1
but I got
bothtpye
Onlineonly
Inpersononly
0
7
6
Please advise me to get through this.
Thank you.
My solution uses double conditional aggregation.
SELECT SUM (CASE WHEN In_Person > 0 AND Online > 0 THEN 1 ELSE 0 END) as bothtype,
SUM (CASE WHEN In_Person > 0 AND Online = 0 THEN 1 ELSE 0 END) as inpersononly,
SUM (CASE WHEN In_Person = 0 AND Online > 0 THEN 1 ELSE 0 END) as onlineonly
FROM (
SELECT Course_name,
SUM(CASE WHEN Course_type='In Person' THEN 1 ELSE 0 END) as In_Person,
SUM(CASE WHEN Course_type='Online' THEN 1 ELSE 0 END) as Online
FROM Course
GROUP BY Course_name
) tot
DEMO Fiddle
SUGGESTION ( using PL/SQL ! ) :
CREATE PROCEDURE countCourses(OUT bothtype INT,OUT Inpersononly INT,OUT Onlineonly INT)
begin
SELECT COUNT(*) INTO bothtype FROM Course;
select COUNT(*) INTO Inpersononly FROM Course
WHERE courseType = "In person";
select COUNT(*) INTO Onlineonly FROM Course
WHERE courseType = "Online";
end;
call countCourses(#bothtype,#Inpersononly,#Onlineonly);
SELECT #bothtype,#Inpersononly,#Onlineonly;
EXPLICATION :
Creating procedure to store the count of each type of course in OUT variable
Call the procedure with convenient parameters
Select out given parameters

AWS Athena create a binary matrix

Is it possible to create a binary matrix in AWS Athena from a table. For example we have the following table:
name
product
John
Bike
John
Shirt
John
Ball
Blake
Shirt
Mike
Ball
Mike
Hat
To be converted to the following:
name
Bike
Shirt
Ball
Hat
John
1
1
1
0
Blake
0
1
0
0
Mike
0
0
1
1
I suggest you to use Case expression:
select name,
sum(case when product = 'bike' then 1 else 0 end) as "Bike",
sum(case when product = 'Shirt' then 1 else 0 end) as "Shirt",
sum(case when product = 'Ball' then 1 else 0 end) as "Ball",
sum(case when product = 'Hat' then 1 else 0 end) as "Hat"
from tableName

Group by one column and return several columns on multiple conditions - T-SQL

I have two tables which I can generate with SELECT statements (joining multiple tables) as follows:
Table 1:
ID
Site
type
time
1
Dallas
2
01-01-2021
2
Denver
1
02-01-2021
3
Chicago
1
03-01-2021
4
Chicago
2
29-11-2020
5
Denver
1
28-02-2020
6
Toronto
2
11-05-2019
Table 2:
ID
Site
collected
deposited
1
Denver
NULL
29-01-2021
2
Denver
01-04-2021
29-01-2021
3
Chicago
NULL
19-01-2020
4
Dallas
NULL
29-01-2019
5
Winnipeg
13-02-2021
17-01-2021
6
Toronto
14-02-2020
29-01-2020
I would like the result to be grouped by Site, having on each column the COUNT of type=1 , type=2, deposited and collected, all of the 4 columns between a selected time interval. Example: (interval between 01-06-2020 and 01-06-2021:
Site
type1
type2
deposited
collected
Dallas
0
1
0
0
Denver
1
0
2
1
Chicago
1
1
0
0
Toronto
0
0
0
0
Winnipeg
0
0
1
1
How about union all and aggregation?
select site,
sum(case when type = 1 then 1 else 0 end) as type_1,
sum(case when type = 2 then 1 else 0 end) as type_2,
sum(deposited) as deposited, sum(collected) as collected
from ((select site, type, 0 as deposited, 0 as collected
from table1
) union all
(select site, null,
(case when deposited is not null then 1 else 0 end),
(case when collected is not null then 1 else 0 end)
from table2
)
) t12
group by site;
Combine your tables 1 and 2 with a join on Site
Use COUNT(CASE WHEN type = 1 then 1 END) as type1 and a similar construct for type 2
Use COUNT(CASE WHEN somedate BETWEEN '2020-06-01' and '2021-06-01' then 1 END) as ... for your dates

How to use conditional group by aggregations correctly

I want to be able to count the total type of apples (organic only) from each continent, broken down by countries; including the total count if they're mixed.
For example, food item B1 is organic golden apples from the USA. Thus there should be a count of "1" golden_bag and "1" for organic. Now, A1 is also organic from Argentina - however, it has both granny and red delicious apples - thus it is counted as "1" mixed_bag and "1" for granny_bag and "1" for red_bag as well.
Finally, E1 and F1 are both fuji apples from laos, but one is organic the other isn't; so total count is 2 fuji_bag and it should have a total count of 1 for organic_fd.
Table X:
food_item | food_area | food_loc | food_exp
A1 lxgs argentina 1/1/20
B1 iyan usa 5/31/21
C1 lxgs peru 4/1/20
D1 wa8e norway 10/1/19
E1 894a laos 5/1/19
F1 894a laos 9/17/19
Table Y:
food_item | organic
A1 Y
B1 Y
C1 N
D1 N
E1 Y
F1 N
Table Z:
food_item | food_type
A1 189
A1 190
B1 191
C1 189
D1 192
E1 193
F1 193
SELECT continent, country,
SUM(organic) AS organic_fd, SUM(Granny) AS granny_bag,
SUM(Red_delc) AS red_bag, SUM(Golden) AS golden_bag,
SUM(Gala) AS gala_bag, SUM(Fuji) AS fuji_bag,
SUM(CASE WHEN Granny + Red_delc + Golden + Gala + Fuji > 1 THEN 1 ELSE 0 END) AS mixed_bag
FROM (SELECT (CASE SUBSTR (x.food_area, 4, 1)
WHEN 's' THEN 'SA' WHEN 'n' THEN 'NA'
WHEN 'e' THEN 'EU' WHEN 'a' THEN 'AS' ELSE NULL END) continent,
x.food_loc country, COUNT(y.organic) AS Organic
COUNT(CASE WHEN z.food_type = '189' THEN 1 END) AS Granny,
COUNT(CASE WHEN z.food_type = '190' THEN 1 END) AS Red_delc,
COUNT(CASE WHEN z.food_type = '191' THEN 1 END) AS Golden,
COUNT(CASE WHEN z.food_type = '192' THEN 1 END) AS Gala,
COUNT(CASE WHEN z.food_type = '193' THEN 1 END) AS Fuji
FROM x LEFT JOIN z ON x.food_item = z.food_item
LEFT JOIN y on x.food_item = y.food_item and y.organic = 'Y'
WHERE x.exp_date > sysdate
GROUP BY SUBSTR (x.food_area, 4, 1), x.food_loc, y.organic) h
GROUP BY h.continent, h.country, h.organic
I'm not getting the correct output, since for example, Laos will show TWICE to account for the organic count and non-organic count. So it will show 1 organic_fd and 0 organic_fd and 1 fuji_bag and the other line will be another 1 fuji_bag. I would like the TOTAL count. (Also, if I add more food items, my mixed_bag shows mostly "1" count for each record/lines).
Below is the desired output:
| continent | country |organic_fd | granny_bag| red_bag| golden_bag| gala_bag|fuji_bag | mixed_bag
| SA | argentina | 1 | 1 | 1 | 0 | 0 | 0 | 1
| SA | peru | 0 | 1 | 0 | 0 | 0 | 0 | 0
| NA | usa | 1 | 0 | 0 | 1 | 0 | 0 | 0
| EU | norway | 0 | 0 | 0 | 0 | 1 | 0 | 0
| AS | laos | 1 | 0 | 0 | 0 | 0 | 2 | 0
So, say I want to add another food item, G1 from Norway and it has 3 types of organic apples: fuji, red, granny... then Norway will now have a count of 1 for the following columns: mixed_bag, organic_fd, fuji_bag, red_bag ,granny_bag (in addition to the previous count of 1 gala_bag). If you add H1, which is exactly the same as G1, then it will now have a total count of 2 for the following: mixed_bag, organic_fd, fuji_bag,red_bag, granny_bag
The query:
WITH
t AS (
SELECT
CASE SUBSTR(X.food_area, LENGTH(X.food_area), 1)
WHEN 's' THEN 'SA'
WHEN 'n' THEN 'NA'
WHEN 'e' THEN 'EU'
WHEN 'a' THEN 'AS'
ELSE NULL
END AS continent,
x.food_loc AS country,
COUNT(DISTINCT CASE Y.organic WHEN 'Y' THEN X.food_item END) OVER (
PARTITION BY x.food_loc
) AS organic_fd,
CASE
WHEN MIN(Z.food_type) OVER (
PARTITION BY x.food_loc, X.food_item
) = Z.food_type AND
MAX(Z.food_type) OVER (
PARTITION BY x.food_loc, X.food_item
) > Z.food_type THEN 1 END AS mixed,
Z.food_type
FROM X
JOIN Y ON X.food_item = Y.food_item
JOIN Z ON Y.food_item = Z.food_item
)
SELECT
continent, country, organic_fd,
COUNT(CASE WHEN food_type = '189' THEN 1 END) AS Granny,
COUNT(CASE WHEN food_type = '190' THEN 1 END) AS Red_delc,
COUNT(CASE WHEN food_type = '191' THEN 1 END) AS Golden,
COUNT(CASE WHEN food_type = '192' THEN 1 END) AS Gala,
COUNT(CASE WHEN food_type = '193' THEN 1 END) AS Fuji,
COUNT(mixed) AS mixed_bag
FROM t
GROUP BY continent, country, organic_fd
You can try this query here: https://rextester.com/TSSH87409.
You have one to many relationship between x and z, and join may produce many rows for each row in x, like in case of A1. So you have to number rows in x at first, this is what my subquery t1 do, except of mapping values. Then group them taking max() for each counted column (granny, organic etc.), like in subquery t2. Finally sum values.
dbfiddle demo
with
t1 as (
select rn, food_item, food_area, food_loc country, food_exp, food_type,
decode(substr(food_area, 4, 1), 's', 'SA', 'n', 'NA', 'e', 'EU', 'a', 'AS') continent,
case organic when 'Y' then 1 else 0 end org,
case when food_type = '189' then 1 else 0 end gra,
case when food_type = '190' then 1 else 0 end red,
case when food_type = '191' then 1 else 0 end gol,
case when food_type = '192' then 1 else 0 end gal,
case when food_type = '193' then 1 else 0 end fuj
from (select rownum rn, x.* from x) x join y using (food_item) join z using (food_item)
where food_exp > sysdate),
t2 as (
select rn, country, continent, max(org) org, max(gra) gra,
max(red) red, max(gol) gol, max(gal) gal, max(fuj) fuj,
case when max(gra) + max(red) + max(gol) + max(gal) + max(fuj) > 1
then 1 else 0
end mix
from t1 group by rn, country, continent)
select continent, country, sum(org) organic_fd, sum(gra) granny, sum(red) red_delc,
sum(gol) golden_bag, sum(gal) gala_bag, sum(fuj) fuji_bag, sum(mix) mixed_bag
from t2
group by continent, country
Above query gave expected output, please test it and adjust if needed. I noticed you use left joins. If there is possibility that for some rows in X there is no data in Y or Z you may have to add nvl()s in calculations. Maybe you should also put mapped, hardcoded values into tables. Hardcoding them is not good practice. Hope this helps :)

Need a SQL query to get data based on condition based on count

I have tables called areadetail and state.
areadetail has these columns:
State Id
Area Id-rural(1) or urban(2)
Population
Sample data:
Stateid AreaID Population
1 1 10
1 2 20
1 2 20
2 1 10
2 2 20
3 1 10
State table has these columns:
State name and state id
Sample data:
State Id StateName
1 Delhi
2 Mumbai
3 Jaipur
Now I need a query to display records like
State name Rural Urban
------------------------------------------
Delhi 3 2
Mumbai 1 1
Jaipur 1 0
I guess AreaID=1 means RURAL and 2 is URBAN then try this query:
SELECT
MAX(s.StateName),
SUM(CASE WHEN ad.AreaID=1 THEN ad.Population ELSE 0 END) as Rural ,
SUM(CASE WHEN ad.AreaID=2 THEN ad.Population ELSE 0 END) as Urban
FROM State as s
LEFT JOIN areadetail as ad on s.Stateid=ad.Stateid
GROUP BY s.Stateid
SQLFiddle demo
Select name,Rural,Urban
from
(
Select state, sum(case when area= 1 then 1 else 0 end) 'Rural',sum(case when area= 2 then 1
else 0 end) 'Urban'
from #Area
group by state
) A
join State S
on A.state = S.state