I'm trying to find a solution to only returns the highest-valued row from a SQL query
I have a query that joins two tables together and then checks how many times the id matches within the different tables (within 'athelete' the id param is unique).
SELECT t.athlete_id, count(a.id) as 'Number of activities' FROM training_session t
INNER JOIN athlete a ON t.athlete_id = a.id
WHERE t.athlete_id = a.id
GROUP BY a.id
The following table is returned
athlete_id Number of activities
1 4
2 1
3 1
4 1
5 1
6 1
The issued problem is that I only want to return the row with the highest number of activities. According to the table above this should be
athlete_id = 1 since it has the greatest amount of activities.
I would appreciate some pointers on how I could improve my query to match these queries.
Use ORDER BY and LIMIT:
SELECT t.athlete_id, count(*) as `Number of activities`
FROM training_session t INNER JOIN
athlete a
ON t.athlete_id = a.id
GROUP BY t.athlete_id
ORDER BY COUNT(*) DESC
LIMIT 1;
I don't think a JOIN is needed for this query:
SELECT t.athlete_id, COUNT(*) as `Number of activities`
FROM training_session t
GROUP BY t.athlete_id
ORDER BY COUNT(*) DESC
LIMIT 1;
And if you want all rows in the event of ties, then this requires a bit more work. I would recommend ranking functions:
SELECT *
FROM (SELECT t.athlete_id, COUNT(*) as `Number of activities`,
RANK() OVER (ORDER BY COUNT(*) DESC) as seqnum
FROM training_session t
GROUP BY t.athlete_id
) t
WHERE seqnum = 1;
Related
We have many old selects like this:
SELECT
tm."ID",tm."R_PERSONES",tm."R_DATASOURCE", ,tm."MATCHCODE",
d.NAME AS DATASOURCE,
p.PDID
FROM TABLE_MAPPINGS tm,
PERSONES p,
DATASOURCES d,
(select ID
from TABLE_MAPPINGS
where (R_PERSONES, MATCHCODE)
in (select
R_PERSONES, MATCHCODE
from TABLE_MAPPINGS
where
id in (select max(id)
from TABLE_MAPPINGS
group by MATCHCODE)
)
) tm2
WHERE tm.R_PERSONES = p.ID
AND tm.R_DATASOURCE=d.ID
and tm2.id = tm.id;
These are large tables, and queries take a long time.
How to rebuild them?
Thank you
You can query the table only once using something like (untested as you have not provided a minimal example of your create table statements or sample data):
SELECT *
FROM (
SELECT m.*,
COUNT(CASE WHEN rnk = 1 THEN 1 END)
OVER (PARTITION BY r_persones, matchcode) AS has_max_id
FROM (
SELECT tm.ID,
tm.R_PERSONES,
tm.R_DATASOURCE,
tm.MATCHCODE,
d.NAME AS DATASOURCE,
p.PDID,
RANK() OVER (PARTITION BY tm.matchcode ORDER BY tm.id DESC) As rnk
FROM TABLE_MAPPINGS tm
INNER JOIN PERSONES p ON tm.R_PERSONES = p.ID
INNER JOIN DATASOURCES d ON tm.R_DATASOURCE = d.ID
) m
)
WHERE has_max_id > 0;
First finding the maximum ID using the RANK analytic function and then finding all the relevant r_persones, matchcode pairs using conditional aggregation in a COUNT analytic function.
Note: you want to use the RANK or DENSE_RANK analytic functions to match the maximums as it can match multiple rows per partition; whereas ROW_NUMBER will only ever put a single row per partition first.
You're querying table_mappings 3 times; how about doing it only once?
WITH
tab_map
AS
(SELECT a.id,
a.r_persones,
a.matchcode,
a.datasource,
ROW_NUMBER ()
OVER (PARTITION BY a.matchcode ORDER BY a.id DESC) rn
FROM table_mappings a)
SELECT tm.id,
tm.r_persones,
tm.matchcode,
d.name AS datasource,
p.pdid
FROM tab_map tm
JOIN persones p ON p.id = tm.r_persones
JOIN datasources d ON d.id = tm.r_datasource
WHERE tm.rn = 1
I have 2 tables: 1st is comment, 2nd is rating
SELECT * FROM comment_table a
INNER JOIN (SELECT comment_id, SUM(rating_value) AS total_rating FROM rating_table GROUP BY comment_id) b
ON a.comment_id = b.comment_id
ORDER BY b.total_rating DESC
I tried the above SQL but doesn't work!
Object is to display a list of comments order by rating points of each comments.
SELECT s.* FROM (
SELECT * FROM comment_table a
INNER JOIN (SELECT comment_id, SUM(rating_value) AS total_rating FROM rating_table GROUP BY comment_id) b
ON a.comment_id = b.comment_id
) AS s
ORDER BY s.total_rating DESC
Nest it inside an another select. It will then output the data in the correct order.
select A."ID","ATHLETE_NAME", "YEAR"
from OLYM."OLYM_ATHLETES" A
JOIN OLYM."OLYM_MEDALS" B ON A."ID" = B."ATHLETE_GAME_ID"
JOIN OLYM."OLYM_GAMES" C ON B."EVENT_ID" = C.ID;
this gave me a table with athlete id, name and year in which he won a medal. is there any way to extract the highest decorated athlete per year form this table or am i missing something?
Table image
If I followed you correctly, you need the athlete with max award in a year. If this is what you required then you can use the analytical function row_number as follows:
SELECT ID, ATHLETE_NAME, YEAR, CNT FROM
(select A."ID","ATHLETE_NAME", "YEAR", COUNT(1) AS cnt,
Row_number() over (partition by "YEAR" order by count(1) desc) as rn
from OLYM."OLYM_ATHLETES" A
JOIN OLYM."OLYM_MEDALS" B ON A."ID" = B."ATHLETE_GAME_ID"
JOIN OLYM."OLYM_GAMES" C ON B."EVENT_ID" = C.ID
group by A."ID","ATHLETE_NAME", "YEAR")
WHERE RN = 1
ORDER BY YEAR
Please use below query, this query will provide you the count of an athlete. You can use HAVING clause further to filter out according to your requirement
select A."ID","ATHLETE_NAME", "YEAR", count(1)
from OLYM."OLYM_ATHLETES" A
JOIN OLYM."OLYM_MEDALS" B ON A."ID" = B."ATHLETE_GAME_ID"
JOIN OLYM."OLYM_GAMES" C ON B."EVENT_ID" = C.ID
group by A."ID","ATHLETE_NAME", "YEAR" order by count(1) desc;
I am trying to figure out a SQL query that will distribute records from one table to another table randomly.
for example :
I have a table of Customers, and I want to assign each a car out of a table of cars.
I want to make sure that the car are randomly distributed, but there is no property of an Customers that would predict which car they would receive.
Customers:
(Jon,Sam,Sara,Jack,Adam,Adrian)
Cars:
(BMW,Dodge,Lexus)
Result:
(Jon-BMW,Sam-Lexus,Sara-BMW,Jack-Dodge,Adam-Dodge,Adrian-BMW)
How can i do that in Oracle SQL?
Here's one option:
SQL> with t as
2 (select u.name ||'-'||a.name comb,
3 row_number() over (partition by u.name order by dbms_random.value(1, n.cnt)) rn
4 from customers u cross join cars a
5 join (select count(*) cnt from cars) n on 1 = 1
6 )
7 select t.comb
8 from t
9 where rn = 1;
COMB
-----------------------------------------
Adam-Lexus
Adrian-BMW
Jack-Lexus
Jon-BMW
Sam-Dodge
Sara-Lexus
6 rows selected.
SQL>
One method that might be more efficient than a full cross join is:
select c.*, cc.car
from (select c.*,
row_number() over (order by dbms_random.value(1, cc.cnt) as seqnum
from customers c cross join
(select count(*) as cnt from cars) cc
) c join
(select cc.*, row_number() over (order by dbms_random.random) as seqnum
from cars cc
) cc
on cc.seqnum = c.seqnum;
if no limit to use all cars and DB resources:
select customer_name||'-'||car_name result
from (
select u.name customer_name, c.name car_name,
row_number() over ( partition by u.name order by dbms_random.value ) ord
from customers u
cross join cars c
)
where ord = 1
I'm having an absolute brain fade
SELECT p.ProductCategory, f.ProductSubCategory, COUNT(*) AS Cnt
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory
GROUP BY p.ProductCategory, f.ProductSubCategory
ORDER BY 1,3 DESC
This shows me the count for each ProductSubCategory, I would like to see only the highest ProductSubCategory per ProductCategory.
I wish to see (I don't care about the Count value)
There are a couple of different ways to do this. One involves joining the results back to themselves and using the max aggregate. But since you are using SQL Server, you can use ROW_NUMBER to achieve the same result:
with cte as (
select p.productcategory, p.ProductSubCategory, COUNT(*) cnt,
ROW_NUMBER() over (partition by p.productcategory order by count(*) desc) rn
from products p
join sales s on p.ProductSubCategory = s.ProductSubCategory
group by p.productcategory, p.ProductSubCategory
)
select *
from cte
where rn = 1
You already got the answer, Please see the following code to. It may help you.
SELECT p.ProductCategory,
f.ProductSubCategory,
COUNT(*) AS Cnt
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory
JOIN (
SELECT p.ProductCategory,
f.ProductSubCategory,
ROW_NUMBER() OVER ( PARTITION BY p.ProductCategory,
f.ProductSubCategory
ORDER BY COUNT(*) DESC) [Row]
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory) Lu
ON P.ProductCategory = Lu.ProductCategory
AND f.ProductSubCategory = Lu.ProductSubCategory
WHERE Lu.Row = 1
GROUP By p.ProductCategory,
f.ProductSubCategory