MySQL join not producing expected results with 'in' function - mysql

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)

Related

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.

Counting votes and if user voted in MySQL table

I have 3 MySQL tables:
Features table:
id name
----------
1 feature 1
2 feature 2
3 feature 3
4 feature 4
5 feature 5
Votes table:
userid featureid
----------------
1 1
1 2
1 3
1 4
2 1
2 2
2 3
2 4
3 1
3 2
3 3
4 1
Users table:
id name
--------
1 John
2 Alice
3 Bob
4 Mark
5 Jane
6 Mary
7 Ann
I need to fetch in single query:
always all features, regardless if they have votes or not
each feature must be listed only once regardless of number of votes even if it has no votes
votes count for each feature listed
a special mark if currently logged user voted for current feature in the list - for example if user 3 is logged in, then list all features with votes count for all users and if user 3 voted for some features have a special field indicating his vote or NULL if he didn't (other data from votes table must be included too so it needs to be LEFT JOINED)
So far I did this:
SELECT *,(SELECT COUNT(*) FROM votes WHERE votes.featureid=features.id) AS "votecnt"
FROM features
LEFT JOIN votes ON votes.featureid=features.id
LEFT JOIN users ON users.id=votes.userid
GROUP BY features.id
It lists all features but has no special field if user 3 voted. I tried with IF, various WHERE conditions and after a lot of tries... ran out of ideas.
Desired output might look like this:
features.id features.name votes.userid votes.otherfields users.id users.name
1 feature 1 4 - 4 Mark
2 feature 2 NULL - NULL NULL
3 feature 3 NULL - NULL NULL
4 feature 4 NULL - NULL NULL
5 feature 5 NULL - NULL NULL
All the features are listed and only those where user 4 voted have other joined tables filled, others are simply NULL. If someone else voted for feature 2 it is still NULL as it is of no relevance for user 4 because in this example user 4 is logged in.
Here is the problem:
http://sqlfiddle.com/#!2/c3d10/3
http://sqlfiddle.com/#!2/c3d10/4
http://sqlfiddle.com/#!2/c3d10/5
http://sqlfiddle.com/#!2/c3d10/6
http://sqlfiddle.com/#!2/c3d10/7
All of above queries in SQLFiddle it should output all 5 features regardless of the userid. So the query must be modified somehow to show all features - even if other people voted for a feature or if there are no votes or if current user voted for feature.
this should do it:
SELECT tmp1.id, name, votecnt, user_id, user_name FROM
(SELECT *,(SELECT COUNT(*) FROM votes WHERE votes.featureid=features.id) AS "votecnt" FROM features) as tmp1
LEFT JOIN (SELECT features.id as feature_id, users.id as user_id, users.name as user_name FROM features
JOIN votes ON votes.featureid=features.id
JOIN users ON users.id=votes.userid
WHERE users.id=3) as tmp2 on tmp1.id = tmp2.feature_id
probably it's not the prettiest sql, and most likely there's also room for optimization
I think you're asking to have all features returned, all counts returned, but only user information if they voted for that feature.
I get the results you're looking for if you specify the userid
select f.id
, f.name
, u.id
, u.name
, v.votecnt
from features f
left join (select featureid, COUNT(userid) votecnt from votes group by featureid) v on v.featureid = f.id
left join votes v1 on v1.featureid = f.id and v1.userid = 4
left join users u on u.id = v1.userid
I chose to specify the userid inside the left join to the votes. Anywhere else and it limits the total number of rows returned.
Results:
1 feature 1 4 Mark 4
2 feature 2 NULL NULL 3
3 feature 3 NULL NULL 3
4 feature 4 NULL NULL 2
5 feature 5 NULL NULL NULL
Example with "Bob"
select f.id
, f.name
, u.id
, u.name
, v.votecnt
from features f
left join (select featureid, COUNT(userid) votecnt from votes group by featureid)v on v.featureid = f.id
left join votes v1 on v1.featureid = f.id and v1.userid = 3
left join users u on u.id = v1.userid
Results:
1 feature 1 3 Bob 4
2 feature 2 3 Bob 3
3 feature 3 3 Bob 3
4 feature 4 NULL NULL 2
5 feature 5 NULL NULL NULL

Select the opposite row of a WHERE clause in a joined jquery result

I have a database with users and games. 1 game can have multiple users so I made a linking table called users_games. The crux is that a game can always only have 2 players since it is a board game. I know which player I am, i have my user_id and my email, but I would like to gain a result that gives me a list of all games I am in WITH the user_id and email of the other fellow. So a query that looks to all games I am in and give the other row, with the name of the player.
My tables:
games
id (int)
board (varchar) representation of the board
users
id (int)
email (varchar)
password (varchar MD5)
users_games
id (int)
user_id (int)
game_id (int)
For clarification this query
SELECT *
FROM `tic_users_games` AS ug
LEFT JOIN tic_users AS u
ON ug.user_id = u.id
RIGHT JOIN tic_games AS g
ON ug.game_id = g.id
And result
id user_id game_id id email password id board created updated
1 1 1 1 ME#gmail.com d56b699830e77ba53855679cb1d252da 1 0|0|0|0|0|0|0|0|0 2012-04-02 16:56:06 2012-04-02 16:56:06
2 2 1 2 FOE1#gmail.com d56b699830e77ba53855679cb1d252da 1 0|0|0|0|0|0|0|0|0 2012-04-02 16:56:06 2012-04-02 16:56:06
3 3 2 2 FOE2#gmail.com d56b699830e77ba53855679cb1d252da 2 0|0|0|0|0|0|0|0|0 2012-04-02 16:56:06 2012-04-02 16:56:06
4 1 2 1 ME#gmail.com d56b699830e77ba53855679cb1d252da 2 0|0|0|0|0|0|0|0|0 2012-04-02 16:56:06 2012-04-02 16:56:06
See: In the above case I just want 2 rows: game_id 1 and 2, with FOE1#... and FOE2#...
Thanks
This should do it for you. The syntax might not be exact for mysql but you should get there. Basically get all users that have games in the user_games table with the same game_ID as the games I am in:
SELECT
User_Games.Game_ID,
Users.ID,
Users.Email
FROM
Users
LEFT JOIN User_Games ON Users.ID = User_Games.User_Id
WHERE
Users.User_ID <> #yourUserID
AND EXISTS
(SELECT
NULL
FROM
User_Games AS MyUserGames
WHERE
User_Games.Game_ID = MyUserGames.Game_ID
AND MyUserGames.User_ID = #yourUserID)
Try this (where #userid represents the user you are searching games for, in this case, 1):
select *
from tic_users_games ug1
left join tic_users_games ug2 on ug1.game_id = ug2.game_id
left join tic_users u on ug2.user_id = u.id
right join tic_games g on ug2.game_id = g.id
where ug1.user_id = #userid
and ug2.user_id <> #userid
Demo: http://www.sqlfiddle.com/#!2/7b0f6/2

mysql select matching results

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
;

Join, Group By and Sum in MySQL

I have the following three tables in a MySQL database in order to give ratings to comments of users:
Users:
id name
-----------
1 Smith
2 Brown
Comments:
id user_id post_id comment
-----------------------------------
1 2 1 Test 1
2 1 1 Test 2
3 1 1 Test 3
Scores:
id user_id comment_id score
------------------------------------
1 1 1 1
Now I want to select all the comments for post_id = 1, plus the username and the sum of all the scores on that specific comment. At first it looks very simple, I came up with this query:
SELECT users.name, comments.comment, SUM(scores.score) AS score
FROM comments
LEFT JOIN users ON users.id = comments.user_id
LEFT JOIN scores ON scores.comment_id = comments.id
WHERE comments.post_id = 1
GROUP BY scores.comment_id
It seems to work, but when there isn't a score for a specific comment, the comment doesn't show up, because MySQL can't GROUP BY NULL, I guess. So, is there any way to include those unrated comments? Like this:
Query result:
name comment score
-------------------------
Brown Test 1 1
Smith Test 2 0
Smith Test 3 0
You could try grouping on comments.id instead perhaps?