mysql select matching results - mysql

I'm trying to find the leagues (lid) where two users are apart of.
Here are my tables:
Table leagues:
*id* lname
--------------
1 Hard C
3 Fun
5 Crazy
Table match:
*userid* *lid*
-----------------
1 1
4 5
1 3
2 1
4 1
4 3
*Are primary keys
match.lid is foreign key to leagues.id (a user cannot not be part of the same league twice)
Here's what I have so far (a start):
SELECT t1.lid, t2.lname
FROM match t1
JOIN leagues t2 on t1.lid = t2.id
So far I managed to join the two tables and get the names. My ultimate goal is to show the lid's where two users are part of the same league, say userid 1 and 4.
userid 1 is a member of lid 1 and 3
userid 4 is a member of lid 5, 1, and 3
Both users meet in league(lid) 1 and 3
So I need a query that shows only the league where both users meet. Like this:
lid lname
--------------
1 Hard C
3 Fun
Since userid 1 and 4 meet in league 1 and 3, the results should show that. I can run two queries for each user and check which leagues both users meet via php, but I think it's more efficient to run one query.

SELECT m1.lid, l.lname FROM
`match` m1, `match` m2, leagues l
WHERE m1.lid = m2.lid AND m1.lid = l.id
AND m1.userid = 1
AND m2.userid = 4

There are a few ways. The most straightforward is:
SELECT id AS lid,
lname
FROM leagues
WHERE id IN
( SELECT lid
FROM match
WHERE userid = 1
)
AND id IN
( SELECT lid
FROM match
WHERE userid = 4
)
;
Another way, which is a bit less direct, but may perform better — you can try it and see — is to use JOIN:
SELECT id AS lid,
lname
FROM leagues
JOIN match AS match1
ON match1.lid = leagues.id
AND match1.userid = 1
JOIN match AS match2
ON match2.lid = leagues.id
AND match2.userid = 4
;

Related

MySQL join not producing expected results with 'in' function

I have a game_players table like this (other columns omitted for brevity):
game_id user_id
1 1
1 3
2 1
2 2
2 4
My intention is to show the user that's logged in only the games they're involved in (e.g. user 2 should only see game 2).
The "where 2 in(select game_players.user_id from game_players)" bit doesn't appear to be working, I get a list of all the games - including the ones user 2 isn't involved in.
select games.game_id as 'game_id',
games.date_game_started as 'date_started',
users.username as 'username',
users.permanent_id as 'permanent_id',
game_players.user_id as 'user_id'
from games
inner join game_players on games.game_id = game_players.game_id
inner join users on game_players.user_id = users.user_id
where 2 in(select game_players.user_id from game_players)
and games.game_active = 1
and game_players.current_turn = 1
group by(games.game_id)
order by field(game_players.user_id, 2) desc,
games.date_game_started asc
Given my test data, I get this result set:
game_id date_started username permanent_id user_id
1 2021-12-15 13:33:17 userc userc 3
2 2021-12-15 13:35:20 Admin admin 1
I should only be getting the second row, because user 2 is only involved in game 2.
I'll admit that my SQL is a bit rusty, please can you help?
I simplified/broke it down and found the answer. I think... so far so good on my testing of it.
Needed to change:
where 2 in(select game_players.user_id from game_players)
to...
where game_players.game_id in(select game_id from game_players where user_id = 2)

many-to-many mysql search looking for team that im not in

I'm struggling with this MySql query.
I have 3 tables.
member
idMember memberEmail
1 joe#dalton.com
2 jack#dalton.com
3 lucky#luke.com
team
idTeam teamName
1 King
2 Lion
3 Cat
teamMember
idMember idTeam
1 1
2 1
3 2
3 3
I need a query that return the team the idMember is not registered.
eg: idMember 1 , not regestered in Team 2 and 3.
any idea?
best regards
Maybe something like this?
SELECT * FROM [team] T
WHERE NOT EXISTS ( SELECT 1 FROM teamMember TM WHERE idMember = [1] AND T.idTeam = TM.idTeam )
Replace [team] with the name of the second table (team id, name) and [1] with the id member you want to search for.
If you are looking fro a particular idmember:
select t.idTeam
from team t
where not exists (select 1
from teamMember tm
where tm.teamId = t.teamId and tm.memberId = 1
);
This is called a correlated subquery. You can do something similar with not in:
select t.idTeam
from team t
where t.idTeam not in (select tm.idTeam
from teamMember tm
where tm.memberId = 1
);
However, not exists is preferable because of the way that not in handles null values in the subquery.

MySQL select rand and exclude users with condition

I need to select random user_id from "user" table, and completely exclude any user_id if current user have any "ongoing" battles with him battles.status
Query:
SELECT user.id
FROM user
LEFT JOIN battles b ON b.uid = user.id AND b.status <> 'ongoing'
WHERE user.id <> 1
ORDER BY RAND( )
LIMIT 1
But the query is not sufficient, because a user can have multiple battles with specific other users, one of them "ongoing" and the others "finished",
My query should select users from the "finished" row.
Tables structure:
user table:
id name
1 John
2 Sarah
3 Jack
4 Andy
5 Rio
battles table:
id uid uid2 status
1 1 2 finished
2 1 2 ongoing
3 2 3 ongoing
4 1 4 finished
5 3 5 finished
If "my" id = "1",
I want to completely exclude any user I have ongoing battle with him, like "2" in the above case and accept all other ids (i.e.3,4 and 5)
You probably want something along the lines of this:
SELECT foe.*
-- Select yourself and join all other users to find potential foes
FROM `user` AS me
INNER JOIN `user` AS foe
ON (me.id <> foe.id)
-- Here we select the active user
WHERE me.`id` = 1
-- Now we exclude foes we have ongoing battles with
-- (your id could be in either uid or uid2)
AND foe.`id` NOT IN (
SELECT `uid` FROM `battles`
WHERE `uid2` = me.`id` AND `status` = 'ongoing'
UNION ALL
SELECT `uid2` FROM `battles`
WHERE `uid` = me.`id` AND `status` = 'ongoing'
);
This will return a list of users which you do not currently have ongoing battles with. You can customise this to return just one of them using LIMIT and random ordering like in your example.

select ids that doesn't have a specific values

I have a table with the schema below:
+---------+--------+
|studentId | course |
+---------+--------+
|1 | 2 |
|1 | 3 |
|1 | 4 |
|1 | 5 |
|2 | 4 |
|2 | 5 |
+---------+--------+
and I want to perform a query to get student Ids that don't have course 2 and 3
select * from students where course not in (2,3);
but it returns Students IDs 1 and 2 and I want it to return Student ID 2 only.
How do I do that?
You could do it like this:
select * from students where studentId not in -- exclude all students from course 2 & 3
(
--find all the students in course 2 & 3
select distinct studentId --could be duplicates might as well grab a distinct list.
from students
where course in (2,3)
)
This answers assumes that OP wants to filter out students that have either course 2 or course 3 or both of them set.
At first, find all students, who have course 2 or 3
SELECT DISTINCT studentId
FROM students
WHERE course IN (2,3)
Then, find all students, who are not in that list
SELECT *
FROM students
WHERE studentId NOT IN (...)
If you only want to return a list of studentIds, without their courses, replace * with DISTINCT studentId.
Put those together:
SELECT DISTINCT studentId
FROM students
WHERE studentId NOT IN (
SELECT DISTINCT studentId
FROM students
WHERE course IN (2,3)
)
Another query using having to filter out students that have courses 2 or 3
select studentId
from students
group by studentId
having sum(course in (2,3)) = 0
This should work:
select
*
from
students s
where
not exists ( select
1
from
students ss
where
ss.studentID = s.studentID
and ss.course in (2,3));
SELECT DISTINCT x.studentid
FROM student x
LEFT
JOIN
( SELECT studentid
FROM student
WHERE course IN(2,3)
GROUP
BY studentid
HAVING COUNT(*) = 2 ) y
ON y.studentid = x.studentid
WHERE y.studentid IS NULL;
(of course, it's highly unlikely that a table holding students and courses would be called student. enrolment might be a better title)
I would recommend using NOT IN and writing a subquery that pulls for each student who is taking courses 2 or 3. That is, if you are looking for students who are not taking course 2 or 3. If you are looking to exclude students who are taking BOTH courses, this will need to change a little bit. Let me know if that is the case.
Start by writing the subquery, which is easy enough:
SELECT *
FROM students
WHERE course = 2 OR course = 3
Then, you can select from your table again using the NOT IN operator:
SELECT DISTINCT studentid
FROM students
WHERE studentid NOT IN (SELECT studentid
FROM students
WHERE course = 2 OR course = 3);
And it works!
JR's query will perform poorly MySQL < 5.6 and only performs an OR not an AND on course.
Try this:
SELECT
id
FROM foo AS missingfoo
LEFT JOIN (
SELECT id FROM foo AS foo1
JOIN foo AS foo2 USING (id)
WHERE foo1.course=2
AND foo2.course=3
) AS z
USING (id) WHERE z.id IS NULL GROUP BY id;

MySQL - Retrieve row value from different table depending on value of row in a table

I have a feeling CASE should be used here but I am not sure. I'm trying to take the sex (m/f) from the general table and depending on the sex, get the build from the corresponding table. For example, when the sex is m, the query should know that by going to the males table and selecting the male_build. I put together an output along with a sample query to give an idea of what I'm trying to accomplish:
members table
member_id | member_name
------------------------
1 Herb
2 Karen
3 Megan
4 Pablo
males table
male_id | member_id | male_build
---------------------------------
1 1 muscular
2 4 fat
females table
female_id | member_id | female_build
-------------------------------------
1 2 thin
2 3 fat
general table
general_id | member_id | sex
-----------------------------
1 1 m
2 2 f
3 3 f
4 4 m
The output should be like this:
1. Herb is a muscular male.
2. Karen is a thin female.
3. Megan is a fat female.
4. Pablo is a fat male.
-> query = "SELECT g.general_id, g.member_id, g.sex,
(CASE when g.sex=m THEN SELECT ma.male_build AS build
FROM males ma WHERE ma.member_id=g.member_id,
CASE when g.sex=f THEN SELECT fe.female_build AS build
FROM females fe WHERE fe.member_id=g.member_id),
m.member_name
FROM members m
JOIN members m ON g.member_id=m.member_id
WHERE g.sex='m' OR g.sex='f'";
Looking for an efficient query for this task.
When you are having to do queries like this, it is a good idea to rethink your database design schemas. That being said, this should work:
SELECT mem.*, g.*, coalesce(m.male_build, f.female_build) as build
from members_table mem
inner join general g on mem.meber_id = g.member_id
left join males m on mem.member_id = m.member_id
left join females f on mem.member_id = f.member_id
Select M.member_name + ' is a '
+ gender_attributes.sex_name
+ ' '
+ gender_attributes.build
From members As M
Join general_table As G
On G.member_id = M. member_id
Join (
Select 'm' As sex, 'male' As sex_name, male_id as id, member_id, male_build As build
From males_table
Union All
Select 'f' As sex, 'female', female_id, member_id, female_build
From females_table
) As gender_attributes
On gender_attributes.sex = G.sex
And gender_attributes.member_id = M.member_id
I'd just have a build_types table and a foreign key on your members table. It may be an edge case, but you can get muscular women, and thin guys.