mySQL: Issue with Left Join - mysql

I have the following query:
SELECT c.`entity_id`,c. p.`name` as parent_id, c.`name`
FROM category c
LEFT JOIN category p WHERE c.`parent_id = p.id
WHERE c.is_active = 1
ORDER BY c.parent_id ASC, c.position ASC;
But I get an error on the first WHERE clause, can anyone spot the error here? Thanks

You have added where clause twice. Try as below :
SELECT c.`entity_id`,c. p.`name` as parent_id, c.`name`
FROM category c
LEFT JOIN category p on c.`parent_id = p.id
Where c.is_active = 1
ORDER BY c.parent_id ASC, c.position ASC;

Related

MySQL: Sorting results before group by statement

Basically, I have a coppermine gallery and I want to show the last 4 updated albums on the homepage. Here's the query that I've got so far. It basically gets the latest pictures. The subquery works fine on it's own but when it comes time to grouping them to get each album on its own, it doesn't seem to be getting the most recent one from the list.
SELECT *
FROM (
SELECT c.cid, c.name AS catname, a.aid, a.title AS albumtitle, a.category, p.aid AS albumid,p.filepath,p.filename,p.ctime AS creationtime,p.title AS pictitle,p.approved
FROM cpg145_pictures AS p LEFT JOIN `cpg145_albums` AS a ON p.aid = a.aid LEFT JOIN `cpg145_categories` AS c ON a.category = c.cid
WHERE p.approved='YES' AND a.category IN (47,48)
ORDER BY p.ctime DESC) AS T
GROUP BY albumid
ORDER BY creationtime DESC
LIMIT 4
I figured out the answer. Apparently, in MariaDB you have to give the subquery a limit for it to be sorted correctly. So:
SELECT *
FROM (
SELECT c.cid, c.name AS catname, a.aid, a.title AS albumtitle, a.category, p.aid AS albumid,p.filepath,p.filename,p.ctime AS creationtime,p.title AS pictitle,p.approved
FROM cpg145_pictures AS p LEFT JOIN `cpg145_albums` AS a ON p.aid = a.aid LEFT JOIN `cpg145_categories` AS c ON a.category = c.cid
WHERE p.approved='YES' AND a.category IN (47,48)
ORDER BY p.ctime DESC
LIMIT 200) AS T
GROUP BY albumid
ORDER BY creationtime DESC
LIMIT 4

Mysql - LEFT JOIN - get first entry

I have this structure in MySql
I am trying to get:
FIRST post, from LAST topic WHERE category is 'News'
In this example it is row from post where id = 2 as marked on image
So far I got this query:
SELECT *
FROM forum_post AS p
LEFT JOIN forum_topic AS t ON p.topic_id = t.id
LEFT JOIN forum_category AS c ON t.category_id = c.id
WHERE c.title = 'News' AND t.id = MAX(t.id)
ORDER BY p.id ASC LIMIT 1
EDIT:
Dirty solution:
SELECT * FROM forum_post
WHERE topic_id = (SELECT MAX(id) FROM forum_topic WHERE category_id = 1)
ORDER BY id ASC LIMIT 1
You can still use a joined query instead of a subquery to get the first post from last topic of your category,note the subquery in join will run only once to get the result set and in your case subquery will run for each iteration
SELECT * FROM
forum_post AS p
JOIN
(SELECT
t.id
FROM
forum_topic AS t
JOIN forum_category AS c
ON t.category_id = c.id
WHERE c.title = 'News'
ORDER BY t.id DESC
LIMIT 1) t
ON p.topic_id = t.id
ORDER BY p.id ASC
LIMIT 1
select fp.* from forum_post fp,
(select min(fp.id) from forum_post fp where topic_id in
(select max(ft.id) from forum_topic ft inner join forum_category fc
on fc.id = ft.category_id where fc.title = 'News'))T
where fp.id = T.id
[In case there are no forum_posts, no row will be returned]
Edit:
Updated [Although I haven't tried executing it]
I haven't test it, but it shoud be something like this:
SELECT fm.remply
FROM forum_topic ft
JOIN forum_category fc
ON ft.category_id = fc.category_id
AND fc.title = 'News'
JOIN forum_post fm
ON ft.id = fm.topic_id
ORDER BY ft.id DESC
,fm.id DESC
LIMIT 1

3 second long queries on 5.8 MB database

I'm running this query;
SELECT p.*,
UNIX_TIMESTAMP(p.upload_date) upload_date_unix,
ph.*,
c.category_name,
c.slug,
(SELECT Count(vote)
FROM picture_votes
WHERE picture_id = p.picture_id) vote_count
FROM pictures p
LEFT JOIN photographers ph
ON ph.photographer_id = p.photographer_id
LEFT JOIN categories c
ON c.category_id = p.category_id
WHERE p.approved = 1
AND ( p.picture_id = p.album_id
OR p.album_id IS NULL )
GROUP BY p.picture_id
ORDER BY p.upload_date DESC
LIMIT 99
And the query takes ~2-3 seconds. If I remove (SELECT count(vote) FROM picture_votes WHERE picture_id = p.picture_id) vote_count the query is like 0.01 seconds. How come it slows the query down so much? picture_votes is only 25,000 rows.
How can I change the query to include the vote count for every picture?
Here's the explain to the query.
Remove your subquery add one more join on picture_votes
SELECT p.*,
Unix_timestamp(p.upload_date) upload_date_unix,
ph.*,
c.category_name,
c.slug,
Count(vote) vote_count
FROM pictures p
LEFT JOIN picture_votes pv ON ( p.picture_id = pv.picture_id )
LEFT JOIN photographers ph
ON ph.photographer_id = p.photographer_id
LEFT JOIN categories c
ON c.category_id = p.category_id
WHERE p.approved = 1
AND ( p.picture_id = p.album_id
OR p.album_id IS NULL )
GROUP BY p.picture_id
ORDER BY p.upload_date DESC
LIMIT 99
Based on the explain for the query, you need index the vote column on picture_votes.
Whenever you have NULL under possible_keys it means that MySQL could not use a relevant index.

MySQL Aggreation query?

I have the following mySQL code:
SELECT
c.categoryId,
c.categoryName, c.categoryParent,
c.categoryDescription,
COUNT(p.productid) as totalProdsInCategory
FROM categories as c
LEFT JOIN normalproducts as p
ON c.categoryId = p.categoryid
WHERE c.categoryId = 41
GROUP BY c.categoryId
ORDER BY c.categoryParent ASC, c.categoryName ASC
I want to be able to include another COUNT column. But this must only be counted as as the products with p.state = "active". Here's my INCORRECT solution
SELECT
c.categoryId,
c.categoryName, c.categoryParent,
c.categoryDescription,
COUNT(p.productid) as totalProdsInCategory,
COUNT(q.productid) as totalActiveProdsInCategory
FROM categories as c
LEFT JOIN normalproducts as p
ON c.categoryId = p.categoryid
WHERE c.categoryId = 41
GROUP BY c.categoryId
ORDER BY c.categoryParent ASC, c.categoryName ASC
Any help? I have no idea where to go from here...
You can use SUM (CASE WHEN p.state = "active" THEN 1 ELSE 0 END) to get the count you're looking for.
SELECT
c.categoryId,
c.categoryName, c.categoryParent,
c.categoryDescription,
COUNT(p.productid) as totalProdsInCategory,
SUM (CASE WHEN p.state = "active" THEN 1 ELSE 0 END) totalActiveProdsInCategory
FROM categories as c
LEFT JOIN normalproducts as p
ON c.categoryId = p.categoryid
WHERE c.categoryId = 41
GROUP BY c.categoryId
ORDER BY c.categoryParent ASC, c.categoryName ASC
Try this:
SELECT
c.categoryId,
c.categoryName, c.categoryParent,
c.categoryDescription,
COUNT(p.productid) as totalProdsInCategory,
SUM(IF(p.state='active',1,0)) as totalActiveProdsInCategory
FROM categories as c
LEFT JOIN normalproducts as p
ON c.categoryId = p.categoryid
WHERE c.categoryId = 41
GROUP BY c.categoryId
ORDER BY c.categoryParent ASC, c.categoryName ASC
This is similar to #Conrad's but a little cleaner in my opinion
This works but maybe doesn't align with the left join approach so much:
SELECT
c.catId,c.catName,
COUNT(p.productId) as totalProdsInCategory,
(SELECT count(*) from product as p where p.catId=1 AND p.state='active') as totalActive
FROM cat as c
LEFT JOIN product as p ON c.catId = p.catId
WHERE c.catId = 1
GROUP BY c.catId
ORDER BY c.catName ASC

how do I fix this LEFT JOIN query?

I have three tables:
products (product_id, title)
comments (comment_id, product_id, user_id, comment, post_date)
bookmarks (user_id, product_id, read_date)
For each product_id in the products table, I wish to retrieve the number of comments with the same product_id, and whose post_date value is greater than the read_date value for the row in the bookmarks table that shares this product_id, and has user_id=22.
If such a row does not exist in the bookmarks table, I want to retrieve the total number of comments for that product_id regardless of read_date.
So far I have
SELECT p.product_id, COUNT( c.comment_id ) comment_count
FROM products p
LEFT JOIN bookmarks b, comments c ON b.product_id = c.product_id
AND b.user_id =22
AND (
c.post_date > b.read_date
)
AND p.product_id = c.product_id
GROUP BY c.product_id
ORDER BY comment_count DESC
This does not give me the expected results. How can I modify it to make it do what I want?
Will it work for you ?
SELECT p.product_id,
COUNT(CASE
WHEN b.read_date IS NOT NULL AND c.post_date >b.read_date THEN c.comment_id
WHEN b.read_date IS NULL THEN c.comment_id
ELSE NULL //optional, CASE has default ELSE NULL
END) as comment_count
FROM products p
LEFT JOIN bookmarks b ON (b.product_id = p.product_id AND b.user_id=22)
LEFT JOIN comments c ON (p.product_id = c.product_id)
GROUP BY p.product_id
ORDER BY comment_count DESC
UPDATE
GROUP BY c.product_id changed to GROUP BY p.product_id
Maybe this will work for you or atleast point you in the right direction.
SELECT p.product_id COUNT( c.comment_id ) comment_count
FROM products p
LEFT JOIN comments c on c.product_id = p.product_id
LEFT JOIN bookmarks b on b.product_id = c.product_id
WHERE (p.product_id IN (
SELECT *
FROM bookmarks b
WHERE b.user_id = 22
)
AND
c.post_date > b.read_date
)
OR
p.product_id NOT IN (
SELECT *
FROM bookmarks b
WHERE b.user_id = 22
)
GROUP BY c.product_id
ORDER BY comment_count DESC