SQL nested query under WHERE - mysql

One of the test questions came by with following schemas, to look for the best doctor in terms of:
Best scored;
The most times/attempts;
For each medical procedures (in terms of name)
[doctor] table
id
first_name
last_name
age
1
Phillip
Singleton
50
2
Heidi
Elliott
34
3
Beulah
Townsend
35
4
Gary
Pena
36
5
Doug
Lowe
45
[medical_procedure] table
id
doctor_id
name
score
1
3
colonoscopy
44
2
1
colonoscopy
37
3
4
ulcer surgery
98
4
2
angiography
79
5
3
angiography
84
6
3
embolization
87
and list goes on...
Given solution as follow:
WITH cte AS(
SELECT
name,
first_name,
last_name,
COUNT(*) AS procedure_count,
RANK() OVER(
PARTITION BY name
ORDER BY COUNT(*) DESC) AS place
FROM
medical_procedure p JOIN doctor d
ON p.doctor_id = d.id
WHERE
score >= (
SELECT AVG(score)
FROM medical_procedure pp
WHERE pp.name = p.name)
GROUP BY
name,
first_name,
last_name
)
SELECT
name,
first_name,
last_name
FROM cte
WHERE place = 1;
It'll mean a lot to be clarified on/explain on how the WHERE clause worked out under the subquery:
How it worked out in general
Why must we match the two pp.name and p.name for it to reflect the correct rows...
...
WHERE
score >= (
SELECT AVG(score)
FROM medical_procedure pp
WHERE pp.name = p.name)
...
Thanks a heap!

Above is join with doctor and medical procedure and group by procedure name and you need doctor names with most attempt and best scored.
Subquery will join by procedure avg score and those who have better score than avg will be filtered.
Now there can be multiple doctor better than avg so taken rank by procedure count so most attempted will come first and then you taken first to pick top one

Related

compare mysql numeric values group_concat of two columns with join

I have 3 tables
1.users
user_id nationality
1 Egyptian
2 Palestinian
3 French
centers
id center_name
1 q
12 y
5 x
23 z
centers_users
student_id center_id
1 12
2 5
3 5
1 23
2 12
what I expect
Nationality center_name count_of_users_from this country
Egyptian y,z 10
Palestinian x,y 33
French x,q 7
I have tried many mysql queries but I cannot get the result I want
Final query I execute:
SELECT * from (SELECT (LENGTH(GROUP_CONCAT(DISTINCT user_id))-ENGTH(REPLACE(GROUP_CONCAT(DISTINCT user_id), ',', ''))) as ss,GROUP_CONCAT( DISTINCT user_id) ,nationality from user where user_id in(SELECT student_id FROM `centers_users`) GROUP by nationality)a
But only get the count with nationality.
When I Join with centers gives me redundancy because I cannot put "ON" condition with
group_concat
How can I implement it?
Thanks..
I think you want to join the tables and aggregate:
select u.nationality,
group_concat(distinct c.center_name) as center_names,
count(distinct user_id) as users_from_this_country
from users u join
user_centers uc
on u.user_id = uc.student_id join
centers c
on c.center_id = uc.center_id
group by u.nationality;
You may be able to use count(*) for users_from_this_country. It depends on how you want to count a user who is in multiple centers in the same country.

Better approach to solving this Mysql query

I have two tables similar to the below examples. I wrote a query to combine the two tables and get the total score of the students. The total score consists of (caone+catwo+examscore). I am searching to see if there are other better approaches to solving this in terms of performance and also syntax wise. Thanks
ca table
name id course ca_cat score
one 1 maths 1 10
one 1 maths 2 6
two 2 maths 1 9
two 2 maths 2 7
exam table
name id course score
one 1 maths 50
two 2 maths 49
My query is shown below
WITH
firstca AS (
SELECT
id,
name,
score,
subject,
FROM
ca
WHERE
cacount =1 ),
secondca AS (
SELECT
id,
name,
score,
subject,
FROM
ca
WHERE
cacount=2),
exam AS (
SELECT
id,
name,
score,
subject,
FROM
exam),
totalscore AS (
SELECT
fca.studentid,
fca.name,
fca.subject,
fca.score AS firstcascore,
sca.score AS secondcascore,
ex.score AS examscore,
(fca.score +sca.score) AS totalca,
(fca.score+sca.score+ex.score) AS totalscores,
FROM
firstca AS fca
JOIN
secondca AS sca
ON
fca.studentid=sca.studentid
AND fca.subject=sca.subject
JOIN
exam AS ex
ON
fca.studentid=ex.studentid
AND fca.subject=ex.subject
The final result table can be similar to this
name id course caone catwo exam totalscore
one 1 maths 10 6 50 66
two 2 maths 9 7 49 65
Is there a better way to write this query, maybe without the with statement or using subqueries and unions?
I wish to learn from every answer here.
Below is for BigQuery Standard SQL
#standardSQL
SELECT name, id, course, caone, catwo, exam,
caone + catwo + exam AS totalscore
FROM (
SELECT name, id, course,
MAX(IF(ca_cat = 1, t2.score, NULL)) AS caone,
MAX(IF(ca_cat = 2, t2.score, NULL)) AS catwo,
ANY_VALUE(t1.score) AS exam
FROM `project.dataset.exam` t1
JOIN `project.dataset.ca` t2
USING (name, id, course)
GROUP BY name, id, course
)
If to apply to sample data from your question - output is
Row name id course caone catwo exam totalscore
1 one 1 maths 10 6 50 66
2 two 2 maths 9 7 49 65

Select a value where another column has the highest value

I have a table with people, their age, and their awesomeness at each age.
What is the simplest query to get John's 'awesomeness' at their maximum age?
People
Name Age Awesomeness
Don 1 12
Don 2 23
Don 3 43
Don 4 30
Sam 1 9
Sam 2 18
Sam 3 59
Sam 4 99
The best query I have:
SELECT awesomeness
FROM people
JOIN (
SELECT MAX(age)
FROM people
WHERE name = 'Don'
) a
ON people.age = a.age
WHERE people.name = 'Don'
Just use order by and limit:
SELECT awesomeness
FROM people
WHERE people.name = 'Don'
ORDER BY age desc
LIMIT 1
You may be wishing to show everyone's score at their maximum age.
You can do that with this query: http://sqlfiddle.com/#!2/b0ff4/1/0
SELECT a.name, a.awesomeness
FROM people a
JOIN (
SELECT name, MAX(age) age
FROM people
GROUP by name
) b ON a.name = b.name AND a.age=b.age

Writing a LIMIT subquery within my SQL query

So I have the following query which fetches active competitions for an organisation, but also aims to fetch the user that is in the lead - for each competition fetched.
The query currently works in that it fetches the competitions, however it currently fetches all the users and I would like to LIMIT 1 on the users fetched, using the SUM(activity_weight) you can see below.
The results come out like this (removed some results to make it easy to see) and in my case, I only want to fetch John and Sally, as they are the leaders of the competitions.
competitionId compName start_date end_date name totalPoints
------------------------------------------------------------
123 First Comp 13-09-09 13-10-09 John 100
123 First Comp 13-09-09 13-10-09 Bob 50
431 Second Comp 13-05-04 13-10-05 Sally 500
431 Second Comp 13-05-04 13-10-05 Jessica 50
I understand that I must use some form of subquery to use the LIMIT, but having a problem nailing the syntax of it.
Any help is much appreciated! THANK YOU
SELECT c.competitionId, c.name, c.start_date, c.end_date, a.userid, u.name,
u.profilePic ,
SUM(activity_weight) AS totalPoints
FROM activity_entries a INNER JOIN users1 u ON u.id = a.userid
INNER JOIN competitions c ON c.competitionId = a.competitionId
WHERE c.organisationId = '$organisation' AND c.start_date < now() AND c.end_date > now()
GROUP BY a.userid, c.competitionId ORDER BY c.id DESC, totalPoints DESC
Try this query
select * from
(select
#rn:=if(#prv=competitionId , #rn+1, 1) as rId,
#prv:=competitionId as competitionId ,
totalPoints,
your_other_columns
from (select * from ...)subquery
join
(select #prv:=0, #rn:=0)tmp
order by
competitionId , totalPoints desc) a
-- only top 2 ordered by points for every competition
where rid<=2
output:
rID competitionId compName start_date end_date name totalPoints
------------------------------------------------------------
1 123 First Comp 13-09-09 13-10-09 John 100
2 123 First Comp 13-09-09 13-10-09 Bob 50
1 431 Second Comp 13-05-04 13-10-05 Sally 500
2 431 Second Comp 13-05-04 13-10-05 Jessica 50
change the last part to where rid<=1 to select top 1

Finding the lone occurence of a value in a table

Lets say I have the following tables.
TABLE L
id name
51 joe
52 sara
53 john
54 david
TABLE M
id l_id
1 51
2 51
3 52
4 53
In table M, there are rows with multiple values for the information in table L. What I am trying to do is select a count of everything which appears just once in table m.
So in the above case, the count would be 2 because they are the l.id's that appear only once in table m:
COUNT(*)
2
How would I go about doing this?
select Count(*)
from
(select l_id From M group by l_id having count(*)=1) m
If you use a count(*) on a sub query which returns just the rows having a count of =1. My mysql is a little bit rusty but I hope the following code will give you an idea.
select count(*) from (
select l_id, count(*) count from m
group by l_id
having count(*) = 1
)
SELECT count(*)
FROM table
HAVING count(id) = 1;