Trouble with join statement for selecting data across tables with MYSQL - mysql

I'm trying to display events that a user has created and events that he has signed up for. I have three tables for this.
//events
| event_id | event_title | event_details | event_timestamp | userid
1 title1 test 1234 1
2 title2 testing2 123 2
//registration_items : event_id references events.event_id
| id | event_id | task_name
1 2 task 1
//registration_signup : id references registration_items.id
| id | userid | timestamp
1 1 1234
Here's the current query I have. Right now it only displays the event the user created. It should display both created events and ones he signed up for
select events.*, registration_items.*, registration_signup.*, users.username from events
INNER JOIN users on users.userid = events.userid
LEFT JOIN registration_items ON registration_items.event_id = events.event_id
LEFT JOIN registration_signup ON registration_signup.id = registration_items.id
WHERE events.userid = '$user_id' OR registration_signup.userid = '$user_id' ORDER BY events.event_timestamp DESC
For userid1 the output should be
Title
title1 (the user created this)
title2 (the user signed up for this)
For userid2 the output should be
Title
title2

select events.*, registration_items.*, registration_signup.*, users.username
from events
INNER JOIN users on users.userid = events.userid
LEFT JOIN registration_items ON registration_items.event_id = events.event_id
LEFT JOIN registration_signup ON registration_signup.id = registration_items.id
WHERE registration_signup.userid = '$user_id'
union
select events.*, registration_items.*, registration_signup.*, users.username
from events
INNER JOIN users on users.userid = events.userid
INNER JOIN registration_items ON registration_items.event_id = events.event_id
INNER JOIN registration_signup ON registration_signup.id = registration_items.id
WHERE events.userid = '$user_id'
ORDER BY events.event_timestamp DESC

I am not sure if it's correct to guess that you have a typo in the sample data. Because your query works the moment you change the user id to 1 for both events, signed up events.. So please take a look at this reference demo and comment if it's not a typo...
SQLFIDDLE DEMO
query: (your query..)
select u.userid,e.event_id as id,
ri.event_id as evt, e.event_title,
ri.task_name,
rs.timestamp,
u.name from events e
INNER JOIN users u on
u.userid = e.userid
LEFT JOIN registration_items ri ON
ri.event_id = e.event_id
LEFT JOIN registration_signup rs ON
rs.id = ri.id
WHERE e.userid = '1' or
rs.userid = '1'
ORDER BY e.event_timestamp DESC
;
Results:
| USERID | ID | EVT | EVENT_TITLE | TASK_NAME | TIMESTAMP | NAME |
------------------------------------------------------------------
| 1 | 1 | 1 | title1 | task 1 | 1234 | john |
| 1 | 2 | 2 | title2 | task 1.2 | 3456 | john |

Related

Get last Message Reply From Conversation

so I have two tables chats and chats_reply. The structure is the following.
chats
--------------------------------------------------
| chat_id | user_one | user_two | created_at
--------------------------------------------------
| 1 | 1 | 2 | something here
--------------------------------------------------
chats_reply
-------------------------------------------------------------------------
| chatReply_id | chat_id | user_id | reply | created_at
-------------------------------------------------------------------------
| 1 | 1 | 1 | Message 1 | something here
-------------------------------------------------------------------------
| 2 | 1 | 2 | Message 2 | something here
-------------------------------------------------------------------------
I'm having a bit of a problem with my query. Let's say my user_id is 1. I want to return a list of all my chats with the last message that was sent. I already have the query that lists all my chats, but it doesn't return the last message it return the first message of the conversation. This is my query:
SELECT
chats.chat_id,
chats.created_at AS ChatTime,
chats_reply.reply,
chats_reply.created_at AS ReplyTime,
chats_reply.status,
users.name,
users.last_name,
users.email
FROM chats
INNER JOIN chats_reply
ON chats.chat_id = chats_reply.chat_id
INNER JOIN users
ON users.user_id =
CASE
WHEN chats.user_one = '1'
THEN chats.user_two
WHEN chats.user_two = '1'
THEN chats.user_one
END
WHERE chats.user_one = '1' OR chats.user_two = '1'
GROUP BY chats_reply.chat_id
ORDER BY chats_reply.chatReply_id DESC
This query returns everything I'd expect, the problem is it return Message 1 from the chats_reply table when I want it to return Message 2. Any help is greatly appreciated.
Use WHERE for filtering. Not GROUP BY:
SELECT c.chat_id, c.created_at AS ChatTime,
cr.reply, cr.created_at AS ReplyTime, cr.status,
u.name, u.last_name, u.email
FROM chats c INNER JOIN
chats_reply cr
ON c.chat_id = cr.chat_id INNER JOIN
users u
ON (u.user_id = c.user_two AND c.user_one = 1) OR
(u.user_id = c.user_one AND c.user_two = 1)
WHERE 1 IN (c.user_one, c.user_two) AND
cr.chatReply_id = (SELECT MAX(cr2.chatReply_id)
FROM chat_reply cr2
WHERE cr2.chat_id = cr.chat_id
);

Multiple joins with multiple conditions with multiple tables

at first my tables:
game
+----+--------------+
| id | game |
+----+--------------+
| 1 | Game1 |
| 2 | Game2 |
| 4 | Game4 |
+----+--------------+
group_game
+---------+----------+
| game_id | group_id |
+---------+----------+
| 1 | 33 |
| 1 | 45 |
| 4 | 33 |
+---------+----------+
groups
+----+------------+----
| id | group_name | ...
+----+------------+----
| 33 | Group33 | ...
| 45 | Group45 | ...
+----+------------+----
users
+---------+----------+----
| user_id | username | ...
+---------+----------+----
| 1 | User1 | ...
| 2 | User2 | ...
+---------+----------+----
users_groups
+---------+----------+
| user_id | group_id |
+---------+----------+
| 1 | 33 |
| 1 | 45 |
| 2 | 45 |
+---------+----------+
What I want to do
Now I want to check wether the current user is in a group which plays "Game4" and if yes the output should be the id and the name of the group.
the current user is "User1" with the ID 1 (table users)
"User1" is in a group with the ID 33 (table users_groups)
The Group-ID 33 belongs to "Group33" (table groups)
The Group with the ID 33 plays the Game with the ID 4 (table group_game)
The Game with the ID belongs to the game "Game4" (table game)
CONCLUSION: Yes, the user is in a group which plays Game4, so output the name of the group ("Group33")
My current code for that (which gives me no rows)
$user_id = $_SESSION["user_id"];
$Game4= "Game4";
$gruppen_dayz = $db->prepare("
SELECT g.group_id, g.group_name
FROM groups g
LEFT JOIN users_groups ug
ON g.group_id = ug.group_id
LEFT JOIN group_game gg
ON g.group_id = gg.group_id
LEFT JOIN game ga
ON ga.id = gg.game_id
WHERE ga.game = ? AND ug.user_id = ?
");
$gruppen_dayz->bind_param('ii', $Game4, $user_id);
I don't know exactly how I should build this query :/
Your where clause is being applied after the joins generate the dataset, negating the left join aspect of your joins. To solve this move the criteria to the join itself so the limits are applied before the joins. Otherwise, the NULL values generated in your left joins are then excluded by your where clause.
There may be other elements as well, this is just the first component I saw.
$user_id = $_SESSION["user_id"];
$Game4= "Game4";
$gruppen_dayz = $db->prepare("
SELECT g.group_id, g.group_name
FROM groups g
LEFT JOIN users_groups ug
ON g.group_id = ug.group_id
AND ug.user_id = ?
LEFT JOIN group_game gg
ON g.group_id = gg.group_id
LEFT JOIN game ga
ON ga.id = gg.game_id
AND ga.game = ?
");
$gruppen_dayz->bind_param('ii', $Game4, $user_id);
---UPDATE ----
Upon further investigation I believe your joins are wrong. Groups doesn't have a group_ID field according to your table structure. Walking though the rest now...
SELECT g.group_id, g.group_name
FROM groups g
LEFT JOIN users_groups ug
ON g.id = ug.group_id
LEFT JOIN group_game gg
ON g.id = gg.group_id
LEFT JOIN game ga
ON ga.id = gg.game_id
WHERE ga.game = ? AND ug.user_id = ?
I might rewrite it as...
SELECT G.Id, G.Group_name
FROM USERS_GROUPS UG
INNER JOIN GROUPS G
on UG.Group_ID = G.ID
INNER JOIN GROUP_GAME GG
on GG.Group_ID = G.ID
INNER JOIN Game GA
on GA.ID = GG.Game_ID
WHERE ga.game = ? AND ug.user_id = ?
I see no value or need for left joins based on your criteria.

sql to find number of attendees (joined) of an event

I'm trying to find number of attendees who have actually joined the sessions of the event. I've 5 tables.
event -> day -> session
attendee
session_attendee
Schema
+------------------------------+
| attendee |
+------------------------------+
| id username password |
| 1 user1 test |
| 2 user2 test |
| ------ |
| event |
| id name |
| 1 event 1 |
| 2 event 2 |
| ----- |
| day |
| id date event_id |
| 1 '2015-06-01' 1 |
| 2 '2015-06-02' 1 |
| 3 '2015-07-01' 2 |
| 4 '2015-07-02' 2 |
| ------ |
| session |
| id name day_id |
| 1 session a 1 |
| 2 session b 1 |
| 3 session c 2 |
| 4 session d 2 |
| ------ |
| session_attendee |
| id session_id attendee_id |
| 1 1 1 |
| 2 2 1 |
| 3 1 2 |
| 4 2 2 |
+------------------------------+
Expectation
+-----------------------------+
| id name attendees |
+-----------------------------+
| 1 'event 1' 2 |
| 2 'event 2' 0/null etc. |
+-----------------------------+
Subquery
SQL query I've tried using Joins but it's returning more than one record (i.e. I can't use it as a subquery)
SELECT count(*) FROM event
INNER JOIN day ON event.id = day.event_id
INNER JOIN session ON day.id = session.day_id
INNER JOIN session_attendee ON session.id = session_attendee.session_id
WHERE event.id = 1
GROUP BY attendee_id
Parent Query
with above subquery substituted
SELECT id, name,
(SELECT COUNT(*) FROM day WHERE day.event_id = event.id) AS days,
(SELECT COUNT(*) FROM event
INNER JOIN day ON event.id = day.event_id
INNER JOIN session ON day.id = session.day_id
INNER JOIN session_attendee ON session.id = session_attendee.session_id
GROUP BY session_attendee.attendee_id) AS attendees
FROM event;
SQL Fiddle
http://sqlfiddle.com/#!9/72ffc
More Work:
SELECT event.id, event.name,
(SELECT count(*) FROM event e INNER JOIN day AS d ON e.id = d.event_id WHERE e.id = event.id) AS total_days,
day.date, session.name, session_attendee.attendee_id
FROM event
LEFT JOIN day ON event.id = day.event_id
LEFT JOIN session ON day.id = session.day_id
LEFT JOIN session_attendee ON session.id = session_attendee.session_id
ORDER BY event.id;
-- COUNT(distinct attendee_id) AS attendees
As soon as I enter COUNT(distinct attendee_id), my result set gets reduced to one row, i.e. I don't get to see records for other events.
Your first query looks basically right with one exception: if you want information for an event, you should aggregate by the event id, not the attendee id:
SELECT e.id, e.name, count(*)
FROM event e INNER JOIN
day d
ON e.id = d.event_id INNER JOIN
session s
ON d.id = s.day_id INNER JOIN
session_attendee sa
ON s.id = sa.session_id
GROUP BY e.id;
Of course, if you want information for only one event, you can replace the GROUP BY with:
WHERE e.id = 1
EDIT:
You want a LEFT JOIN to keep all the events:
SELECT e.id, e.name, count(distinct sa.attendee_id)
FROM event e LEFT JOIN
day d
ON e.id = d.event_id LEFT JOIN
session s
ON d.id = s.day_id LEFT JOIN
session_attendee sa
ON s.id = sa.session_id
GROUP BY e.id;
Try this
SELECT event.id, name,
(SELECT COUNT(*) FROM day WHERE day.event_id = event.id) AS days,
b.number_of_attendee
FROM event
left join (
SELECT a.id, count(*) as number_of_attendee from
(
SELECT event.id, attendee_id FROM event
INNER JOIN day ON event.id = day.event_id
INNER JOIN session ON day.id = session.day_id
INNER JOIN session_attendee ON session.id = session_attendee.session_id
group by event.id, attendee_id
) as a
group by a.id) as b
on b.id = event.id
which has the result like
id name days number_of_attendee
1 Event 1 2 2
2 Event 2 2 (null)

getting latest data in one to many relation table

i would like to fetch data from table a,b,c but order by most recent data of table response
table casework has this structure ( simplified):
casework_id | problem | user_id
------------+-----------+-------
1 | Problem1 | 1
2 | Problem2 | 2
3 | Problem3 | 1
4 | Problem4 | 3
table user has this structure ( simplified):
user_id | name
--------+-----------------
1 | peter
2 | Sam
3 | Tom
4 | Steve
table response has this structure ( simplified):
response_id | response | casework_id | created
------------+-----------+--------------+-------
1 | responce1 | 1 | 2012-10-14 11:28:31
2 | responce2 | 1 | 2012-9-10 11:28:31
3 | responce3 | 1 | 2012-9-2 11:28:31
4 | responce4 | 3 | 2012-8-3 11:28:31
4 | responce5 | 3 | 2012-8-2 11:28:31
I am looking the query to fetch data order by latest responce and group by casework_id
I. e. required out put is
casework_id | problem | name | responce | created
------------+-----------+-------+-----------+---------
1 | Problem1 | peter | responce1 | 2012-10-14 11:28:31
2 | Problem2 | Sam | Null | Null
3 | Problem3 | peter | responce4 | 2012-8-3 11:28:31
4 | Problem4 | Tom | Null | Null
I would be most grateful if one of you kind people could point me in the right direction.
You can use the following:
select c.casework_id,
c.problem,
u.name,
r2.response,
r1.created
from casework c
left join user u
on c.user_id = u.user_id
left join
(
select max(created) created, casework_id
from response r
group by casework_id
) r1
on c.casework_id = r1.casework_id
left join response r2
on r1.created = r2.created
and r1.casework_id = r2.casework_id
See SQL Fiddle with Demo
If you want to include both the user that created the casework and then who responsed, then you will want to join on the user table twice:
select c.casework_id,
c.problem,
u1.name CreatedByName,
r2.response,
r1.created,
u2.name ReponseName
from casework c
left join user u1
on c.user_id = u1.user_id
left join
(
select max(created) created, casework_id
from response r
group by casework_id
) r1
on c.casework_id = r1.casework_id
left join response r2
on r1.created = r2.created
and r1.casework_id = r2.casework_id
left join user u2
on r2.user_id = u2.user_id
See SQL Fiddle with demo
I have not tested it, but it might give you an idea
select c.casework_id, c.problem,
(select name from user u where u.user_id = c.user_id ),
(select r.reponse from response r where r.casework_id = c.casework_id ORDER BY r.created DESC LIMIT 1),
(select r.created from response r where r.casework_id = c.casework_id ORDER BY r.created DESC LIMIT 1),
from casework c
SELECT responce.casework_id, problem, name, responce, created
FROM responce
JOIN
(SELECT casework_id, problem, name
FROM casework JOIN user
ON casework.userid=user.userid) AS A
ON responce.casework_id=A.casework_id
ORDER BY responce, responce.casework_id
Try this
select c.caseword_id, c.problem, u.name, response.response, responce.created from asework c inner join user u on u.user_id = c.user_id left outer join select casework_id from response having max(created) group by casework_id) responsedata on responsedata.casework_id = c.casework_id

LEFT JOIN 3 columns to get username

I have three columns I need to join which comes from 3 different tables,
Contributions table:
+-----------+---------------------+
| record_id | contributor_user_id |
+-----------+---------------------+
| 1 | 2 |
+-----------+---------------------+
| 1 | 5 |
+-----------+---------------------+
Members table:
+--------------+---------+
| username | user_id |
+--------------+---------+
| Test | 1 |
+--------------+---------+
| Test2 | 5 |
+--------------+---------+
| Test3 | 6 |
+--------------+---------+
Records table:
+---------+-----------+
| user_id | record_id |
+---------+-----------+
| 28 | 1 |
+---------+-----------+
For what I need to return is the username and user_id for displaying the record owner. Also, display the username and the user_id, but this can be multiple (more than 1+ user). I've tried this:
SELECT usr.username,
usr.user_id,
rec.record_id,
contrib.record_id,
contrib.contributor_user_id
FROM
(
records rec
INNER JOIN members usr ON rec.user_id = usr.user_id
# this returns records as NULL
LEFT OUTER JOIN contributions contrib ON rec.record_id = contrib.record_id AND contrib.contributor_user_id = usr.user_id
# this works, but I need the username to be displayed too
LEFT OUTER JOIN contributions contrib ON rec.record_id = contrib.record_id
)
WHERE rec.record_id = 1
Try nesting the join for contributing users inside of the left join to contributions.
SELECT u.username, u.user_id, r.record_id, u2.username as ContributorName, u2.user_id as ContributorId
FROM records r
INNER JOIN members u
ON r.user_id = u.user_id
LEFT JOIN contributions c
INNER JOIN members u2
ON c.contributor_user_id = u2.user_id
ON r.record_id = c.record_id
WHERE r.record_id = 1
SELECT
usr.username AS record_owner
, usr.user_id AS record_owner_id
, rec.record_id
, con.contributor_user_id AS contributor_id
, contributors.username AS contributor_name
FROM
records rec
INNER JOIN
members usr
ON rec.user_id = usr.user_id
LEFT OUTER JOIN
contributions con
ON rec.record_id = con.record_id
INNER JOIN
members contributors
ON con.contributor_user_id = contributors.user_id
WHERE
rec.record_id = 1