mysql subquery where value appears twice or more - mysql

I have two tables as below (MYSQL)
ENTRY table
Event_id | Horse_id | Place
101 101 1
101 102 2
101 201 3
101 301 4
102 201 2
103 201 3
201 101 1
301 301 2
401 102 7
HORSE table
Horse_id Name
101 Flash
102 Star
201 Boxer
301 Daisy
401 Snowy
I need to list the horse_id and name of horses that place (1, 2 or 3) two times or more.
best I can come up with which is not near it I know (need to do a subquery)
select horse_tbl.horse_id, horse_tbl.name
from horse_tbl
left join entry_tbl
on horse_tbl.horse_id = entry_tbl.horse_id
where place<4(
select count(horse_id)>1));
Any help would be greatly appreciated

Your query is on the right track, but instead of using a WHERE clause to check the place, you should be using GROUP BY along with conditional aggregation in the HAVING clause:
SELECT
h.horse_id,
h.name
FROM horse_tbl h
LEFT JOIN entry_tbl e
ON h.horse_id = e.horse_id
GROUP BY
h.horse_id,
h.name
HAVING SUM(CASE WHEN e.place IN (1, 2, 3) THEN 1 ELSE 0 END) >= 2
Output:
Demo here:
Rextester

Related

SQL LEFT JOIN 3 TABLES AND USING COUNT AND GROUP BY

I have 3 tables, users, branches and states
TABLE USERS
name code_branch
1 ANA 100
2 BEN 101
3 CARLA 102
4 DAN 100
5 ED 100
TABLE BRANCHES
code_branch branch_name code_state
1 100 BRANCH 100 A
2 101 BRANCH 101 A
3 102 BRANCH 102 C
4 103 BRANCH 103 D
5 104 BRANCH 104 E
6 105 BRANCH 105 F
TABLE STATES
code_state state_name
1 A STATE A
2 B STATE B
3 C STATE C
4 D STATE D
5 E STATE E
and i want the result as per below
state_name total_user
1 STATE A 4
2 STATE B 0
3 STATE C 1
4 STATE D 0
5 STATE E 0
My sql
SELECT s.code_state, COUNT(u.code_branch ) AS total
FROM ((states s
LEFT JOIN branches b ON s.code_state = b.code_state )
LEFT JOIN users u.code_branch = b.code_branch)
GROUP BY s.code_state;
and the result is
STATE TOTAL
A 4
B 0
C 1
D 0
E 0
I Want to show state_name instead of code_state in my query result above.
then i change on the first line like this
SELECT **s.state_name**, COUNT(u.code_branch ) AS total
and like this
SELECT **s.state_name, s.code_state** , COUNT(u.code_branch ) AS total
but get the error
Msg 8120, Level 16, State 1, Line 44
Column 's.state_name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Try adding the group by in the select statement?
SELECT **s.state_name, s.code_state** , COUNT(u.code_branch ) AS total
Group by **s.state_name, s.code_state**

Relation similarity calculation in sql (also called collaborative filtering user-user)

I have a kind of social network dataset where users follow other users.
The data is structured in one table like that:
from_user_id to_user_id event_date
100 201 2020-12-18 00:00:00
101 200 2020-12-18 00:00:00
102 200 2020-12-18 00:00:00
102 201 2020-12-18 00:00:00
103 201 2020-12-18 00:00:00
103 204 2020-12-18 00:00:00
106 201 2020-12-18 00:00:00
106 204 2020-12-18 00:00:00
106 205 2020-12-18 00:00:00
107 205 2020-12-18 00:00:00
given a list of user_ids stored in another table (called top_1000), I would like to retrieve the 3 other users from this list of 1000 who share the most 'followers' in common.
Sample top_1000 table:
user_id
200
201
202
203
204
205
I have 0 idea on how to start with this one.... I guess a self join is probably needed though.
As we can see 100, 103 and 106 are following 201, but 106 also follows 204 and 205, therefore the output should be something like
to_user_id suggested_user_id rank count
200 201 1 1
201 204 1 2
201 206 2 1
You can get all pairs of users that have followers in common (assuming "following" is the "to" column) using a self join:
select f.from_user_id, f2.from_user_id as suggested_user_id, count(*) as followers_in_common
from follows f
follows f2
on f2.to_user_id = f.to_user_id and
f2.from_user_id <> f.from_user_id
where exists (select 1 from top_1000 t where f.from_user_id = t.user_id) and
exists (select 1 from top_1000 t where f2.from_user_id = t.user_id)
group by f.from_user_id, f2.from_user_id;
The where clause limits the followers but not the followed based on your top_1000 table.
You can then get the top three using window functions:
select ff.*
from (select f.from_user_id, f2.from_user_id as suggested_user_id,
count(*) as followers_in_common,
row_number() over (partition by f.from_user_id order by count(*) desc) as seqnum
from follows f
follows f2
on f2.to_user_id = f.to_user_id and
f2.from_user_id <> f.from_user_id
where exists (select 1 from top_1000 t where f.from_user_id = t.user_id) and
exists (select 1 from top_1000 t where f2.from_user_id = t.user_id)
group by f.from_user_id, f2.from_user_id
) ff
where seqnum <= 3;

MySQL three table join with sum

I have three tables
Student
studenid stuname
101 john
102 aron
103 mary
104 lucy
Subject
studenid subjid subjname
101 1 maths
102 2 science
103 3 computer
104 4 english
Marks
subjid mark
1 50
2 40
3 55
4 60
1 40
2 55
3 60
I want output like this where studenid (sum of mark as total)
studenid stuname mark
101 john 90
102 aron 95
103 mary 115
104 lucy 60
Thank you in advance for yout help, i want output like this even join query or subquery which is best for timing
This just requires a straight left join across all tables, with an aggregation by student.
SELECT
st.studenid,
st.stuname,
COALESCE(SUM(m.mark), 0) AS mark
FROM Student st
LEFT JOIN Subject su
ON st.studenid = su.studenid
LEFT JOIN Marks m
ON su.subjid = m.subjid
GROUP BY
st.studenid,
st.stuname;
Demo
Note that if studenid be a primary key in the Student table, then strictly we would only need to aggregate by this column alone.

MySQL query find matching column based on another column?

Sorry I don't know how to word the question's title.
I have a table like this
Prod Part Number
0001 101 3
0001 102 2
0001 103 1
0002 101 3
0002 102 2
0002 103 4
0003 101 2
0003 102 3
0003 103 6
0004 101 3
0004 102 2
0004 103 1
I want to find the product that has the correct number per part for all parts.
So something like
SELECT Prod from table
WHERE (Number of Part(101)) = 3
AND (Number of Part(102)) = 2
AND (Number of Part(103)) = 1
Output would be:
Prod
0001
0004
How can I achieve that?
You could use some inner join
select t1.Prod from
( select Prod
from my_table
where part = 101
and Number = 3 ) t1
inner join
( select Prod
from my_table
where part = 102
and Number = 2 ) t2 on t1.Prod = t2.Prod
inner join
( select Prod
from my_table
where part = 103
and Number = 1 ) t3 on t1.Prod = t3.Prod
http://sqlfiddle.com/#!9/014fe4/8
Through conditional aggregation:
SELECT Prod,
SUM(CASE WHEN Part = 101 AND Number = 3 OR
Part = 102 AND Number = 2 OR
Part = 103 AND Number = 1
THEN 1 ELSE 0 END) sum
FROM tbl
GROUP BY Prod
HAVING sum = 3
This will give you an extra column. If it's a problem then wrap everything into another SELECT.

MySQL Retrieving data from two tables using inner join syntax

My two tables are
Entry
event_id competitor_id place
101 101 1
101 102 2
101 201 3
101 301 4
102 201 2
103 201 3
second table lists prizes on offer for the events
Prize
event_id place money
101 1 120
101 2 60
101 3 30
102 1 10
102 2 5
102 3 2
103 1 100
103 2 60
103 3 40
From this I am looking to show all the information from the Entry table alongside the amount of money they won for their respected placing. If they failed to place in the money then a 0 will be displayed.
Any help would be appreciated.
try this:
SELECT a.Event_ID,
a.Competitor_ID,
a.Place,
COALESCE(b.money, 0) as `Money`
FROM entry a left join prize b
on (a.event_id = b.event_ID) AND
(a.place = b.Place)
hope this helps.
EVENT_ID COMPETITOR_ID PLACE MONEY
101 101 1 120
101 102 2 60
101 201 3 30
101 301 4 0 -- << this is what you're looking for
102 201 2 5
103 201 3 40
Try this:
select e.*, coalesce(p.money, 0) money from entry e
left join prize p
on e.event_id = p.event_id and e.place = p.place
You can play with the fiddle here.
SELECT * FROM Entry NATURAL LEFT JOIN Prize;
If you absolutely want 0 instead of NULL for the "money" when no prize was won (but how can you differentiate between a prize of 0 and no prize?):
SELECT Entry.*, COALESCE(money, 0) AS money FROM Entry NATURAL LEFT JOIN Prize;
See them both on sqlfiddle.