Adding a JOIN to query resulting in a fail - php

I am trying to add my users table to my existing query so that I can match the users.id with the forum_topics.topic_creator, so I can match those and enable myself to assign that with that users username.
This is my original query.
$query2 = mysqli_query($con,"SELECT t.*, COUNT(p.topic_id)
AS tid2 FROM forum_topics AS t JOIN forum_posts
AS p on t.id = p.topic_id WHERE t.category_id = ".$cid."
GROUP BY t.id DESC")
I then tried doing this..
$query2 =mysqli_query($con,"SELECT t.*, COUNT(p.topic_id)
AS tid2 FROM forum_topics AS t JOIN forum_posts
AS p on t.id = p.topic_id WHERE t.category_id = ".$cid."
INNER JOIN users AS u
ON t.topic_creator = u.id
GROUP BY t.id DESC")
or die ("Query2 failed: %s\n".($query2->error));
I am getting the fail message.
What am I doing wrong?

WHERE clause should come after join:
SELECT t.*, COUNT(p.topic_id) AS tid2
FROM forum_topics AS t JOIN
forum_posts AS p on t.id = p.topic_id INNER JOIN
users AS u ON t.topic_creator = u.id
WHERE t.category_id = ".$cid."
GROUP BY t.id DESC
EDIT:
To select the username as well:
SELECT t.*,u.username, COUNT(p.topic_id) AS tid2
FROM forum_topics AS t JOIN
forum_posts AS p on t.id = p.topic_id INNER JOIN
users AS u ON t.topic_creator = u.id
WHERE t.category_id = ".$cid."
GROUP BY t.id DESC

The WHERE clause has to be placed after the INNER JOIN.
$query2 =mysqli_query($con,"SELECT t.*, COUNT(p.topic_id)
AS tid2 FROM forum_topics AS t
JOIN forum_posts AS p ON t.id = p.topic_id
INNER JOIN users AS u ON t.topic_creator = u.id
WHERE t.category_id = ".$cid."
GROUP BY t.id DESC")
or die ("Query2 failed: %s\n".($query2->error));

Try this
SELECT t.*, COUNT(p.topic_id) AS tid2
FROM forum_topics t
JOIN forum_posts p ON (t.id = p.topic_id )
INNER JOIN users u ON (t.topic_creator = u.id)
WHERE t.category_id = ".$cid."
GROUP BY t.id DESC`

Related

how to use where condition in both parts of union in mysql

I'm using php and mysql for making a chat application.
I want to use a where condition in both parts of union but this not working
my code is :
$Query = "(SELECT u.userid, u.photo, u.username FROM `last_activity` AS la INNER JOIN user AS u ON la.userid = u.userid LEFT join private_chat pc ON u.userid = pc.sender_id WHERE la.last_activity_date BETWEEN '2020-09-21 10:20:00' AND '2020-09-21 10:30:00' AND u.username like '%amit%' ORDER BY pc.created_date DESC) UNION (SELECT userid, photo, username FROM user u LEFT join private_chat pc ON u.userid = pc.sender_id WHERE u.u_type = '2')";
and i want like and this not works
$Query = "(SELECT u.userid, u.photo, u.username FROM `last_activity` AS la INNER JOIN user AS u ON la.userid = u.userid LEFT join private_chat pc ON u.userid = pc.sender_id) UNION (SELECT userid, photo, username FROM user u LEFT join private_chat pc ON u.userid = pc.sender_id ) WHERE la.last_activity_date BETWEEN '2020-09-21 10:20:00' AND '2020-09-21 10:30:00' AND u.u_type = '2' AND u.username like '%amit%' ORDER BY pc.created_date DESC";
SELECT *
FROM
(
SELECT u.userid, u.photo, u.username, pc.created_date
FROM `last_activity` AS la
INNER JOIN `user` AS u ON la.userid = u.userid
LEFT JOIN private_chat pc ON u.userid = pc.sender_id
WHERE la.last_activity_date BETWEEN '2020-09-21 10:20:00' AND '2020-09-21 10:30:00'
AND u.username LIKE '%amit%'
UNION ALL
SELECT userid, photo, username, pc.created_date
FROM `user` u
LEFT JOIN private_chat pc ON u.userid = pc.sender_id
WHERE u.u_type = '2'
) a
ORDER BY a.created_date DESC;

Selecting data from database with sql

i have a sql sub-select to list how many orders there are and their total value:
SELECT u.name,
(SELECT COUNT(*) FROM orders o WHERE o.user_id=u.id
) AS order_count,
(SELECT SUM(oi.quantity * p.price)
FROM orders AS o
INNER JOIN order_items AS oi
ON oi.order_id = o.id
INNER JOIN products AS p
ON p.id = oi.product_id
WHERE o.user_id=u.id
) AS total_price
FROM users u
ORDER BY total_price DESC
Any ideas how can i do that without sub-select?
You can convert the correlated subqueries (O(N^2) performance) into LEFT JOIN
SELECT u.name,
o.order_count,
o2.total_price
FROM users u left join (
SELECT user_id, COUNT(*) order_count
FROM orders
GROUP BY user_id
) o
on u.id = o.user_id
left join (
SELECT o.user_id, SUM(oi.quantity * p.price) total_price
FROM orders o
INNER JOIN order_items oi
ON oi.order_id = o.id
INNER JOIN products p
ON p.id = oi.product_id
GROUP BY o.user_id
) o2 on u.id = o2.user_id
ORDER BY total_price DESC;
You can use Left Join
SELECT u.NAME,
AS order_count,
total_price
FROM users u
LEFT JOIN (SELECT Count(*) AS order_count,
user_id
FROM orders
GROUP BY user_id) p
ON o.user_id = u.id
LEFT JOIN (SELECT Sum(oi.quantity * p.price) AS total_price,
o.user_id
FROM orders AS o
INNER JOIN order_items AS oi
ON oi.order_id = o.id
INNER JOIN products AS p
ON p.id = oi.product_id
GROUP BY o.user_id) so
ON so.user_id = u.id
ORDER BY total_price DESC
Here's the same query with one sub query (NOTE not tested for syntax but you get the idea):
select u.name, count(*) orderCount, sum(totalOrder) total order
from users u
join (select userid, o.id, sum(oi.quantity * p.price) totalorder
from orders o
join order_items as oi on oi.order_id = o.orderid
join products p on oi.product_id = p.id
group by userid, o.id) x
on u.id = x.user_id
group by u.name

Add a WHERE clause to a MySQL query

I have this MySQL query that works really well. What it's doing is displaying all the filenames (filename) in a database, along with the poster of that filename and then any user who is tagged with that filename (cp.user_id). Later on in the script I explode the tagGroup.
I have a created a new field in the tbl_collab table called 'approved' which can either be 'yes' or 'no' and I want to know how to add a WHERE clause to my query so only the users where approved="yes" in tbl_collab are displayed. How can I do this? Many thanks.
"SELECT up.id, up.file, up.title, p.user_name, p.user_id, GROUP_CONCAT(CONCAT(cp.user_id, '~', cp.user_name) SEPARATOR '|') AS tagGroup
FROM tbl_uploads up
LEFT JOIN tbl_users p ON up.user_id = p.user_id
LEFT JOIN tbl_collab c ON up.file = c.file
LEFT JOIN tbl_users cp ON cp.user_id = c.collab_userid
GROUP BY up.file ORDER BY up.id DESC LIMIT ? , ?"
This is how I am exploding the tagGroup.
$tag_array = explode('|' , $tagGroup);
foreach($tag_array as $tag) {
list($uid,$uname) = explode('~',$tag,2);
You can add this condition in where clause like
"SELECT up.id, up.file, up.title, p.user_name, p.user_id, GROUP_CONCAT(CONCAT(cp.user_id, '~', cp.user_name) SEPARATOR '|') AS tagGroup
FROM tbl_uploads up
LEFT JOIN tbl_users p ON up.user_id = p.user_id
LEFT JOIN tbl_collab c ON up.file = c.file
LEFT JOIN tbl_users cp ON cp.user_id = c.collab_userid
WHERE c.approved = 'yes'
GROUP BY up.file ORDER BY up.id DESC LIMIT ? , ?"
Or you can add this condition in joining condition like
"SELECT up.id, up.file, up.title, p.user_name, p.user_id, GROUP_CONCAT(CONCAT(cp.user_id, '~', cp.user_name) SEPARATOR '|') AS tagGroup
FROM tbl_uploads up
LEFT JOIN tbl_users p ON up.user_id = p.user_id
LEFT JOIN tbl_collab c ON up.file = c.file AND c.approved = 'yes'
LEFT JOIN tbl_users cp ON cp.user_id = c.collab_userid
GROUP BY up.file ORDER BY up.id DESC LIMIT ? , ?"
Add WHERE c.approved = 'yes'to your sql query ;) or change the JOIN-condition to LEFT JOIN tbl_collab c ON (up.file = c.file AND c.approved = 'yes')

optimizing the 3 queries into one

I am just trying to figure out on how to optimize the below sequence of queries into a single query.
To be specific, below queries are just like alerts to be displayed to user when he logins into his account.
$sq = "SELECT COUNT(*) as totm FROM login as l
JOIN msgs m on m.id = l.id
WHERE m.tstamp > l.mtstamp AND l.id = $id;";
$sq .= "SELECT COUNT(*) as totp FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 0 AND u.id = $id;";
$sq .= "SELECT COUNT(*) as totq FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 1 AND u.id = $id";
Right now Iam using mysqli_multi_query() to run this multiple queries.
However I have managed to cut it down into a single query
$sq = "SELECT m.totm,p.totp FROM login as l
JOIN info as u on u.id = l.id
LEFT JOIN (SELECT tstamp,id,COUNT(*) as 'totm' FROM msgs GROUP BY id) m
ON m.id = l.id AND m.tstamp > l.mtstamp
LEFT JOIN (SELECT tstamp,cid,type,id,COUNT(*) as 'totp' FROM pst
GROUP BY id) p
ON p.cid = u.cid AND p.tstamp > l.ptstamp AND p.type = 0
AND p.id <> l.id WHERE l.id = $id
LEFT JOIN (SELECT tstamp,cid,type,id,COUNT(*) as 'totp' FROM pst
GROUP BY id) p
ON p.cid = u.cid AND p.tstamp > l.ptstamp AND p.type = 1
AND p.id <> l.id WHERE l.id = $id LIMIT 1";
When I have tried the single query with EXPLAIN STATEMENT the query ouput is too bad, many rows are affected.
When I have performed the same on three queries individually, the result was good. I am not sure should I run multiple queries or try single query.
After googling I have found that groupBY causes severe overhead in joins and for many rows. kindly anyone let me know what would be the better way to approach this. Can anyone me help me for writing a more optimized query. Thank you. Any help is greatly appreciated.
If you're trying to retrieve the count for a specific id, then I recommend combining your queries as subqueries in the select. There's no sense in using GROUP BY since you're looking for the count of a specific id.
SELECT
(SELECT COUNT(*) FROM login as l
JOIN msgs m on m.id = l.id
WHERE m.tstamp > l.mtstamp AND l.id = $id) totm,
(SELECT COUNT(*) FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 0 AND u.id = $id) totp,
(SELECT COUNT(*) FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 1 AND u.id = $id) totq
Contrast this to retrieving counts for every id in which case a GROUP BY on id would be useful:
SELECT t1.id,t1.totm,t2.totp,t3.totq
FROM
(SELECT l.id, COUNT(*) as totm FROM login as l
JOIN msgs m on m.id = l.id
WHERE m.tstamp > l.mtstamp
GROUP BY l.id) t1
LEFT JOIN (SELECT u.id, COUNT(*) as totp FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 0
GROUP BY u.id) t2 ON t1.id = t2.id
LEFT JOIN (SELECT u.id, COUNT(*) as totq FROM info as u
JOIN pst as p on p.cid = u.cid
JOIN login as l on l.id = u.id
WHERE p.tstamp > l.ptstamp AND p.id <> u.id
AND p.type = 1
GROUP BY u.id) t3 ON t2.id = t3.id

Filter MySQL result w/ empty row

I have searched high and low to filter my mysql query but WHERE NOT NULL does not work. I hope somebody could help me. I have some columns that are empty named 'path'. And I want to filter these out.
My query:
SELECT
p.path, p.title, p.body, p.post_date, u.username FROM pages p
LEFT JOIN users u ON p.post_author = u.id
ORDER BY p.id ASC
How can I get this done? Thanks.
SELECT
p.path, p.title, p.body, p.post_date, u.username
FROM pages p
LEFT JOIN users u ON p.post_author = u.id
WHERE
p.path IS NOT NULL AND
p.path <> ''
ORDER BY p.id ASC
So does this help or you are asking something different?
try with php to check the empty field:
$query = "SELECT
p.path, p.title, p.body, p.post_date, u.username FROM pages p
LEFT JOIN users u ON p.post_author = u.id
ORDER BY p.id ASC";
$result = mysql_query($query);
while( $row = mysql_fetch_assoc($result) ){
// Check for empty record
if( !empty($row['path']) ){
echo $row['path'];
}
}
Try this one, this might work.
SELECT
p.path, p.title, p.body, p.post_date, u.username FROM pages p
LEFT JOIN users u ON p.post_author = u.id
WHERE p.path IS NOT NULL AND p.path <> ''
ORDER BY p.id ASC

Categories