I've build the following query:
(SELECT
privatemsgs.id,
privatemsgs.useradn,
privatemsgs.useraid,
privatemsgs.title,
privatemsgs.created,
privatemsgs.timee,
privatemsgs.isread,
u.photo AS creatorphoto,
privatemsgs.relatedto
FROM privatemsgs
LEFT JOIN
users AS u ON(privatemsgs.useraid = u.id)
WHERE userbid='5'
AND relatedto=0 and bdel=1)
UNION ALL
(SELECT
privatemsgs.id,
privatemsgs.useradn,
privatemsgs.useraid,
privatemsgs.title,
privatemsgs.created,
privatemsgs.timee,
privatemsgs.isread,
u.photo AS creatorphoto,
rel.relatedto
FROM privatemsgs AS rel
JOIN privatemsgs ON(rel.relatedto = privatemsgs.id)
LEFT JOIN
users AS u ON(rel.useraid = u.id)
WHERE rel.userbid='5')
GROUP BY id
ORDER BY timee DESC
This query select all Privatemsgs from the tables, and acting like mail,FOR EX:
If I sent a msg to user b, and user b answered me. I want to display the msg in inbox and outbox of each user.
A comment to private msg marked as "relatedto" the id of the main msg.
The query works, but duplicate the msgs in display (same msg display many times)
I tried to do "GROUP BY id" in order to fix it but i got the error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'GROUP BY id ORDER BY timee DESC'
THANK YOU!!
First, as per PM 77's comment, a union instead of a union all will solve your problem of duplicates. You don't need a group by clause at all.
Second, you might have a logic error. The top have of your union query has this:
FROM privatemsgs
LEFT JOIN
users AS u ON(privatemsgs.useraid = u.id)
WHERE userbid='5'
AND relatedto=0 and bdel=1)
If any of those fields in the where clause are in the users table, your left join has become an inner join. To keep it as a left join, you have to put all the filters in the join, like this:
FROM privatemsgs
LEFT JOIN
users AS u ON privatemsgs.useraid = u.id
AND userbid='5'
AND relatedto=0 and bdel=1)
Related
I have a big data problem with MySQL.
I have:
a users table with 59033 rows, and
a user_notes table with 8753 rows.
But when I search which users have user note in some dates.
My query like this :
SELECT u.*, rep.name as rep_name FROM users as u
LEFT JOIN users as rep on rep.id = u.add_user
LEFT JOIN authorization on authorization.id = u.authorization
LEFT JOIN user_situation_list on user_situation_list.user_situation_id = u.user_situation
WHERE
EXISTS(
select * from user_notes
where user_notes.note_user_id = u.id AND user_notes.create_date
BETWEEN "2017-10-20" AND "2017-10-22"
)
ORDER BY u.lp_modify_date DESC, u.id DESC
Turn it around -- find the ids first; deal with the joins later.
SELECT u.*,
( SELECT rep.name
FROM users AS rep
WHERE rep.id = u.add_user ) AS rep_name
FROM (
SELECT DISTINCT note_user_id
FROM user_notes
WHERE create_date >= "2017-10-20"
AND create_date < "2017-10-20" + INTERVAL 3 DAY
) AS un
JOIN users AS u ON u.id = un.note_user_id
ORDER BY lp_modify_date DESC, id DESC
Notes
No GROUP BY needed;
2 tables seem to be unused; I removed them;
I changed the date range;
User notes needs INDEX(create_date, note_user_id);
Notice how I turned a LEFT JOIN into a subquery in the SELECT list.
If there can be multiple rep_names, then the original query is "wrong" in that the GROUP BY will pick a random name. My Answer can be 'fixed' by changing rep.name to one of these:
MAX(rep.name) -- deliver only one; arbitrarily the max
GROUP_CONCAT(rep.name) -- deliver a commalist of names
Rewriting your query to use a JOIN rather than an EXISTS check in the where should speed it up. If you then group the results by the user.id it should give you the same result:
SELECT u.*, rep.name as rep_name FROM users as u
LEFT JOIN users as rep on rep.id = u.add_user
LEFT JOIN authorization on authorization.id = u.authorization
LEFT JOIN user_situation_list on user_situation_list.user_situation_id = u.user_situation
JOIN user_notes AS un
ON un.note_user_id
AND un.create_date BETWEEN "2017-10-20" AND "2017-10-22"
GROUP BY u.id
ORDER BY u.lp_modify_date DESC, u.id DESC
I have a query that looks up people's full names based on their record ID's in a table called users. The full names are tied to their roles in another table (table1). This requires multiple joins to the users table:
SELECT table1.id, users.full_name AS "Requester",
users.full_name AS "Approver,"
users.full_name AS "Ordered By",
users.full_name AS "Received By"
FROM table1
JOIN users AS users
ON table1.requester_id = users.id
JOIN users AS users2
ON table1.approver_id = users2.id
JOIN users AS users3
ON table1.ordered_by = users3.id
JOIN users AS users4
ON table1.received_by = users4.id
WHERE table1.deleted_record !=1;
The problem I'm having is with ordered_by and received_by. Often, they don't yet exist, because the order has neither been ordered nor received, so the ID for each can be 0, which has no corresponding value in the userstable. When I run this query, I should get back all 475 records that exist, but I only get back 365, because of those 0 values. How can I modify this query to make sure all rows are returned, even if ordered_by and/or received_by = 0?
First, your primary table driving the query should be table1. Then, you are using JOIN instead of LEFT JOIN. LEFT JOIN will give you a null result if no link, but not fail. In which case, you might have to use an IF for your fields value
SELECT table1.id, req.full_name AS "Requester",
app.full_name AS "Approver",
ordr.full_name AS "Ordered By",
rec.full_name AS "Received By"
FROM table1
LEFT JOIN users AS req
ON table1.requester_id = req.id
LEFT JOIN users AS app
ON table1.approver_id = app.id
LEFT JOIN users AS ordr
ON table1.ordered_by = ordr.id
LEFT JOIN users AS rec
ON table1.received_by = rec.id
WHERE table1.deleted_record !=1;
This should do it
You are looking for left join:
SELECT t1.id, ur.full_name AS "Requester",
ua.full_name AS "Approver,"
uo.full_name AS "Ordered By",
urv.uo AS "Received By"
FROM table1 t1 LEFT JOIN
users ur
ON t1.requester_id = ur.id LEFT JOIN
users ua
ON t1.approver_id = ua.id LEFT JOIN
users uo
ON t1.ordered_by = uo.id LEFT JOIN
users urv
ON t1.received_by = urv.id
WHERE t1.deleted_record <> 1;
Note that I changed the aliases on the users references from fairly meaningless u1, u2, etc. to ua, uo, and so on. Also, these need to be used in the SELECT to get the right full name.
I was using this:
SELECT res.*, rac.*, u.*, t.*, c.*
FROM Results res
INNER JOIN Races rac USING (RaceID)
INNER JOIN Users u USING (UserID)
INNER JOIN Teams t USING (TeamID)
INNER JOIN Cars c USING (CarID)
WHERE res.SeasonNumber = '$SeasonNumber' AND res.LeagueID = '$LeagueID' AND Position = '1' AND ResultConfirmed = '1'
ORDER BY Position ASC
Which works fine, but I've since realised I need to have CarID added in to Results table, but when I add it in, it gives me the error that the field is ambiguous. What I'd like to do is get the Car name from Cars table where CarID joins Cars and Results. When I try to do this though:
SELECT res.*, rac.*, u.*, t.*, c.*
FROM Results res
INNER JOIN Races rac USING (RaceID)
INNER JOIN Users u USING (UserID)
INNER JOIN Teams t USING (TeamID)
INNER JOIN Cars c USING (res.CarID)
WHERE res.SeasonNumber = '$SeasonNumber' AND res.LeagueID = '$LeagueID' AND Position = '1' AND ResultConfirmed = '1'
ORDER BY Position ASC
I get the following error:
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near '.CarID) WHERE res.SeasonNumber = '1' AND res.LeagueID = '1' AND
Position = '1' ' at line 6
You can replace your USING clause with ON(),in USING() clause i guess you add the columns name that are same in other table you are joining but you placed the join in last and using alias res mysql won't allow this
INNER JOIN Cars c ON(res.CarID =c.CarID)
If you need to use USING() clause you need to adjust the join placements like
SELECT res.*, rac.*, u.*, t.*, c.*
FROM
Cars c
INNER JOIN Results res USING (CarID)
INNER JOIN Races rac USING (RaceID)
INNER JOIN Users u USING (UserID)
INNER JOIN Teams t USING (TeamID)
WHERE res.SeasonNumber = '$SeasonNumber' AND res.LeagueID = '$LeagueID' AND Position = '1' AND ResultConfirmed = '1'
ORDER BY Position ASC
But ON() clause is more readable form
i have troubles finding the right sql-statement
I have 3 tables:
1.) Messages
2.) Mail_Inbox
3.) Mail_Outbox
New Messages are stored in Messages and its ID is stored in both other tables.
User can delete their mails from inbox and outbox folder.
I want du parse a single sql-statement to delete all entries from Messages where no entries in Inbox AND Outbox with the corresponding ID exsits.
I still found a working statement, which tells me the right IDs, but i can't find a way to delete them.
SELECT Messages.Message_ID
FROM `Messages`
LEFT JOIN Mail_Inbox On Messages.Message_ID = Mail_Inbox.Message_ID
LEFT JOIN Mail_Outbox On Messages.Message_ID = Mail_Outbox.Message_ID
WHERE ISNULL(Mail_Outbox.Mail_ID) AND ISNULL(Mail_Outbox.Mail_ID)
I tried this:
DELETE FROM Messages
WHERE Message_ID = (SELECT Messages.Message_ID
FROM `Messages`
LEFT JOIN Mail_Inbox On Messages.Message_ID = Mail_Inbox.Message_ID
LEFT JOIN Mail_Outbox On Messages.Message_ID = Mail_Outbox.Message_ID
WHERE ISNULL(Mail_Outbox.Mail_ID) AND ISNULL(Mail_Outbox.Mail_ID))
But got this error: You can't specify target table 'Messages' for update in FROM clause
:-(
It is not possible to use a table you want to delete from inside s subquery as per DELETE-documentation
SELECT
Messages.Message_ID
FROM `Messages`
LEFT JOIN Mail_Inbox ON Messages.Message_ID = Mail_Inbox.Message_ID
LEFT JOIN Mail_Outbox ON Messages.Message_ID = Mail_Outbox.Message_ID
WHERE ISNULL(Mail_Inbox.Mail_ID) AND ISNULL(Mail_Outbox.Mail_ID)
becomes
DELETE
Messages
FROM `Messages`
LEFT JOIN Mail_Inbox ON Messages.Message_ID = Mail_Inbox.Message_ID
LEFT JOIN Mail_Outbox ON Messages.Message_ID = Mail_Outbox.Message_ID
WHERE ISNULL(Mail_Inbox.Mail_ID) AND ISNULL(Mail_Outbox.Mail_ID)
DELETE FROM Messages WHERE Message_ID IN (some subquery that select Message_IDs)
Your current subquery will give you all Message_IDs and will delete all messages because you use a LEFT JOIN. Use INNER JOIN.
I am building a custom forum in CodeIgniter. I have four primary tables: parents(categories), children(boards), threads, and messages(replies). The thread table only contains the thread id, author, title, date, and the id of the first message. When a thread is viewed, it takes the column "first_msg_id" to retrieve the content of the thread.
I would like to create a query that gets the count of all the replies in a specific board. Basically, any message that doesn't match a thread's first_msg_id field. Here is what I have so far:
$query = "
SELECT
m.message_id, m.thread_id
t.thread_id, t.first_msg_id
FROM forum_messages AS m
LEFT JOIN forum_threads AS t ON t.first_msg_id != m.message_id
WHERE t.child_id = ".$board_id."
ORDER BY m.message_id";
This is the error I'm getting:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.thread_id, t.first_msg_id FROM forum_messages AS m ' at line 3
Here are my tables:
Update
Ok, so now that I got my query working(well, fixed the error), it's not doing what I want... I think I have my logic wrong. I wrote a script that created 40 new threads in one board. None of them have replies. When I use mysql num rows with the query I made, I get a result of 1560. It should return 0. Why is this happening??? Lol.
Got it working.
You are missing a comma after m.thread_id
Something like
SELECT
m.message_id, m.thread_id,
t.thread_id, t.first_msg_id
FROM forum_messages AS m
LEFT JOIN forum_threads AS t ON t.first_msg_id != m.message_id
WHERE t.child_id = ".$board_id."
ORDER BY m.message_id
Comma missing , after m.thread_id
Try with -
$query = "SELECT m.message_id, m.thread_id, t.thread_id, t.first_msg_id ....
More appropriate -
$query = "
SELECT
m.message_id, m.thread_id,
^
-------------------------|
t.thread_id, t.first_msg_id
FROM forum_messages AS m
LEFT JOIN forum_threads AS t ON t.first_msg_id != m.message_id
WHERE t.child_id = ".$board_id."
ORDER BY m.message_id
";