Select records from joint tables - sql

Got two tables:
tblJumper
JumperID
JumperName
and
tblWidthScored
ScoreID
fkJumperID
fkScoredWidth
Tables related by tblWidthScored.fkJumperID = tblJumper.JumperID
Table Contains following data:
tblJumper
1 Tom
2 Jerry
3 Bugs
tblWidthScored
1 1 5,72m
2 2 6,13m
3 1 5,80m
4 3 6,40m
5 2 6,30m
6 3 6,20m
What I'm trying to get is a list of each Jumpers personla best:
Tom 5,80m
Jerry 6,30m
Bugs 6,40m
Tried SELECT DISTINCT... in various forms but didn't succeed in any way.
Anyone couldl give a hint, please?
Thanks!

Although I think this is just a Join question and appropriate articles could be found on the web, I'll post one of the answers...
SELECT
J.JumperName,
S.Score
FROM tblJumper as J
INNER JOIN(
SELECT
fkJumperID,
Max(fkScoredWidth) as Score
FROM tblWidthScored
GROUP BY
fkJumperID
) as S on J.JumperID = S.fkJumperID
The hints you're asking for are in your actual question actually:
You're trying to find personal bests! That means some kind of aggregation: Maximum.
You're trying to find personal bests distinctly. Not "the best score amongst whole jumpers" but every person's personal best distinctly. That means some kind of distinction or grouping that you can partition the score datas people by people: Group By Clause

you can try this query. for this type of query, you have to use Group BY Clause with Sub-query.
SELECT JumperName, innertblWidthScored
FROM tblJumper INNER JOIN(SELECT fkJumperID,
Max(fkScoredWidth) as innertblWidthScored
FROM tblWidthScored
GROUP BY fkJumperID) WidthScored
on tblJumper.JumperID = WidthScored.fkJumperID
SQL FIDDLE DEMO

You could as well start with the JOIN, and do the GROUP BY afterwards. And if your sample output does actually suggest a sort order, you need an ORDER BY, too.
SELECT
JumperName
, MAX(fkScoredWidth) PersonalBest
FROM tblJumper
JOIN tblWidthScored
ON JumperID = fkJumperID
GROUP BY JumperName
ORDER BY MAX(fkScoredWidth) DESC;
SQL Fiddle

From result it seems that you want to retrieve jumper with its best score
try this -
select
a.jumperName,
b.bestScore
from tblJumper a, (
select
max(fkScoredWidth) as bestScore,
fkJumperID
from tblWidthScored
group by
fkJumperID
) b on b.fkJumperID = a.JumperID
order by
a.JumperID

Related

SQL Help - Think I need a subquery

I have wrote the following query.
SELECT pro.[Id], COUNT(*) AS Count
FROM {Task} tsk
JOIN {profile} pro ON tsk.[ProfileId]=pro.[Id]
GROUP BY
pro.[Id]
HAVING
COUNT(*) > 1
This returns the records I am interested in but it returns the following...
ID Count
12345 3
21254 2
25458 2
I now need to take it a stage further and I think I would need to use the query I have wrote within another query to get what I need.
I basically need to see the underlying data in the count e.g. task-number. So the end result will look something like this based on the above example.
ID Count
12345 123-345
12345 135-564
12345 136-985
21254 124-856
21254 135-854
25458 214-854
25458 365-850
Am I correct in thinking I need a subquery to do this and how would I go about it?
Thanks
You could go with a CTE, count, filter then join
WITH CTE AS (
SELECT pro.[Id], COUNT(*) AS Count
FROM {Task} tsk
JOIN {profile} pro ON tsk.[ProfileId]=pro.[Id]
GROUP BY
pro.[Id]
HAVING
COUNT(*) > 1
)
SELECT tsk.[Id], tsk.[ProfileId] FROM CTE
JOIN {Task} tsk ON CTE.[Id] = tsk.[ProfileId]

find an average of a column using group with inner join and then filtering through the groups

I've been trying to solve an sqlite question where I have two tables: Movies and movie_cast.
Movies has the columns: id, movie_title, and `score. Here is a sample of the data:
11|Star Wars|76.496
62|2001:Space Odyssey|39.064
152|Start Trek|26.551
movie_cast has the columns: movie_id, cast_id, cast_name, birthday, popularity. Here is a sample.
11|2|Mark Hamill|9/25/51|15.015
11|3|Harrison Ford|10/21/56|8.905
11|5|Peter Cushing|05/26/13|6.35
IN this case movies.id and movie_cast.movie_id are the same.
The question is to Find the top ten cast members who have the highest average movie scores.
Do not include movies with score <25 in the average score calculation.
▪ Exclude cast members who have appeared in two or fewer movies.
My query is as below but it doesn't seem to get me the right answer.
SELECT movie_cast.cast_id,
movie_cast.cast_name,
printf("%.2f",CAST(AVG(movies.score) as float)),
COUNT(movie_cast.cast_name)
FROM movies
INNER JOIN movie_cast ON movies.id = movie_cast.movie_id
WHERE movies.score >= 25
GROUP BY movie_cast.cast_id
HAVING COUNT(movie_cast.cast_name) > 2
ORDER BY AVG(movies.score ) DESC, movie_cast.cast_name ASC
LIMIT 10
The answers I get are in the format cast_id,cat_name,avg score.
-And example is: 3 Harrison Ford 52.30
I've analyzed and re-analyzed my logic but to no avail. I'm not sure where I'm going wrong. Any help would be great!
Thank you!
This is how I would write the query:
SELECT mc.cast_id,
mc.cast_name,
PRINTF('%.2f', AVG(m.score)) avg_score
FROM movie_cast mc INNER JOIN movies m
ON m.id = mc.movie_id
WHERE m.score >= 25
GROUP BY mc.cast_id, mc.cast_name
HAVING COUNT(*) > 2
ORDER BY AVG(m.score) DESC, mc.cast_name ASC
LIMIT 10;
I use aliases for the tables to shorten the code and make it more readable.
There is no need to cast the average to a float because the average in SQLite is always a real number.
Both COUNT(movie_cast.cast_name) can be simplified to COUNT(*) but the 1st one in the SELECT list is not needed by your requirement (if it is then add it).
The function PRINTF() returns a string, but if you want a number returned then use ROUND():
ROUND(AVG(m.score), 2) avg_score

Grouping multiple rows into one string postgres for each position in select

I have a table education that has a column university. For each of the rows in the table I want to find 3 most similar universities from the table.
Here is my query that finds 3 most similar universities to a given input:
select distinct(university),
similarity(unaccent(lower(university)),
unaccent(lower('Boston university')))
from education
order by similarity(unaccent(lower(university)),
unaccent(lower('Boston university'))) desc
limit 3;
It works fine. But now I would like to modify this query so that I get two columns and a row for each existing university in the table: the first column would be the university name and the second would be the three most similar universities found in the database (or if its easier - four columns where the first is the university and the next 3 are the most similar ones).
What should this statement look like?
You could use an inline aggregated query:
with u as (select distinct university from education)
select
university,
(
select string_agg(u.university, ',')
from u
where u.university != e.university
order by similarity(
unaccent(lower(u.university)),
unaccent(lower(e.university))
) desc
limit 3
) similar_universities
from education e
This assumes that a given university may occur more than once in the education table (hence the need for a cte).
I think a lateral join and aggregation does what you want:
select e.university, e2.universities
from education e cross join lateral
(select array_agg(university order by sim desc) as universities
from (select e2.university,
similarity(unaccent(lower(e2.university)),
unaccent(lower(e.university))
) as sim
from education e2
order by sim desc
limit 3
) e2
) e2;
Note: The most similar university is probably the one with the same name. (You can filter that out with a where clause in the subquery.)
This returns the value as an array, because I prefer working with arrays rather than strings in Postgres.

postgres - finding unique users which have specific records

I need some help completing the following query with postgres.
I have the following table for example: (this is the essence of what im trying to accomplish)
lets call it - table_user_flags
user_id flag
1 1
1 2
2 1
2 3
3 1
3 2
3 3
I need to find all users which have records with specific flags (under flag column, at least 1 record with each flag)
Example:
all users which have records with flags 1,3 (i.e 1 and 3) answer (user_id 2,3)
(but also would like to make it simple to extend so that i can request flags 1,2,3,4,5 etc)
I tried many things, unfortunately I was not able to articulate the situation well enough to find an answer on google.
My best guess (which is lame and possibly faulty) is (and provided flags array - $flag_arr)
select a.user_id
from table_user_flags a, table_user_flags b
where a.flag = $flag_arr[0] and b.flag = $flag_arr[1] and a.user_id=b.user_id
but this strategy is slow, and also will only work if i need 2 flags, when i need more than 2 flags I will need to write specific queries for each length of the flags_arr.
How can I solve this?
I will appreciate any help!
SELECT user_id
FROM table_user_flags
WHERE flag IN (1,2)
GROUP BY user_id
HAVING COUNT(DISTINCT flag)=2;
Fiddle
select user_id
from table_user_flags as t
inner join (select unnest($flag_arr) as flag) as c on c.flag = t.flag
group by t.user_id
having count(distinct t.flag) = array_length($flag_arr, 1);
or
select user_id
from table_user_flags as t
where t.flag = any($flag_arr)
group by t.user_id
having count(distinct t.flag) = array_length($flag_arr, 1);
sql fiddle demo
you can use count(*) if user_id, flag_id is unique inside the table

calculate rank in highscore from 2 tables

i have a trivia game and i want to reward users for 2 events:
1) answering correctly
2) sending a question to the questions pool
i want to query for score and rank of a specific player and i use this query:
SELECT (correct*10+sent*30) AS score, #rank:=#rank+1 AS rank
FROM ( trivia_players
JOIN ( SELECT COUNT(*) AS sent, senderid
FROM trivia_questions
WHERE senderid='$userid'
) a
ON trivia_players.userid=a.senderid
)
ORDER BY score DESC
and it works if the player is in both tables i.e answered correctly AND sent a question.
but it doesn't work if a player hasn't sent a question
any idea how to fix this query? ($userid is the given parameter)
thanks!
Thanks Tom! only problem is the ranks are not correct:
userid score rank
58217 380 1
12354 80 3
32324 0 2
I would probably do it like this:
SELECT
user_id,
score,
rank
FROM
(
SELECT
TP.user_id,
(TP.correct * 10) + (COUNT(TQ.sender_id) * 30) AS score,
#rank:=#rank + 1 AS rank
FROM
Trivia_Players TP
LEFT OUTER JOIN Trivia_Questions TQ ON
TQ.sender_id = TP.user_id
GROUP BY
TP.user_id,
TP.correct
ORDER BY
score DESC
) AS SQ
WHERE
SQ.user_id = $user_id
I don't use MySQL much, so the syntax may not be perfect. I think that you can use a subquery like this in MySQL. Assuming that MySQL handles COUNT() by only counting rows with a non-null value for , this should work.
The keys are that you do a COUNT over a non-null column from Trivia Questions so that it counts them up by the user and you need to use a subquery so that you can get ranks for everyone BEFORE constraining to a particular user id.
Have you tried using a RIGHT JOIN or LEFT JOIN? Just off the top of my head!