Limit a query inside a JOIN? - mysql

I have a query which pulls out all articles and their categories (that matches the current category).
I want it to fetch only 5 articles per category. how can i do it?
the query:
SELECT a.* FROM
Articles a
LEFT JOIN Articles_category b
ON a.id=b.article_id
LEFT JOIN Categories c
ON c.id = b.category_id
LEFT JOIN Articles_category ac1
ON ac1.main = 1 AND a.id = ac1.article_id AND ac1.position > 0
WHERE c.id = '14'
ORDER BY b.main DESC
I want it to select only 5 articles tops for each category.

You can't do it with that query. You would have to loop a similar query to that, based on the category id. You could do it in a stored procedure, or loop the query repeatedly in code.

Related

MySQL SUM left join show all categories even with the sum of 0

I wish to select all categories based on the sum of scores of a set of data, even if the set of data does not include the categories. However, it always only display categories with actual data no matter what I try.
I have created the following SQLFiddle http://sqlfiddle.com/#!9/52a127/3
For ease of view, I'll paste the select statement here:
SELECT categories.id, IFNULL(SUM(raw_data.score), 0) as total
FROM categories
LEFT JOIN raw_data ON categories.id = raw_data.category_id
WHERE
(raw_data.quarter = '2018Q2' OR !raw_data.quarter) AND
raw_data.broker_id = 2
GROUP BY categories.id
ORDER BY total DESC
As you can see from the fiddle, it only displays 2 categories, but I wish to select all 6 and have 0 for those with no results.
Any help is appreciated, thanks!
You need to move condition from WHERE to ON clause:
SELECT categories.id, IFNULL(SUM(raw_data.score), 0) as total
FROM categories
LEFT JOIN raw_data ON categories.id = raw_data.category_id
AND (raw_data.quarter = '2018Q2' OR !raw_data.quarter)
AND raw_data.broker_id = 2
GROUP BY categories.id
ORDER BY total DESC;
SQLFiddle Demo

Any way to combine these 3 SQL Queries Together?

I have 3 separate queries at the moment that I'm trying to combine together so it is more efficient.
The reason I'm putting them together is so that I can sort all of the results by submitdate, as of right now they are sorted by submitdate but are separated by each query.
First is
Query that gets all posts that I have commented on that have new comments
SELECT DISTINCT p.*,c.submitdate as MostRecentSubmitDate
FROM posts p
INNER JOIN comments c
ON c.postid = p.id
WHERE c.submitdate > (
SELECT MAX(c2.submitdate)
FROM comments c2
WHERE c2.postid = c.postid
AND c2.deviceID = ?
)
Second is
Query that gets most recent replies on my posts.
SELECT p.PostTitle,p.id AS PostID,c1.id AS CommentID, c1.comment, q.LatestCommentDate, c1.deviceID
FROM (SELECT c.postid, MAX(c.SubmitDate) AS LatestCommentDate
FROM comments c GROUP BY c.postid) q
INNER JOIN posts p ON q.postid = p.id and ? = p.deviceiD
INNER JOIN comments c1 ON q.LatestCommentDate = c1.submitDate
Third is
Query that gets the amount of votes on each of my posts
SELECT * FROM posts
WHERE DEVICEID = ?
AND PostVotes > 0
ORDER BY SUBMITDATE
You can use UNION to combine all your queries together.
Rules to make a UNION
The number and the order of the columns must be the same in all queries.
The data types must be compatible.
query 1
UNION
query 2
UNION
query 3
ORDER BY ...

Inner join statement with limit in one of three tables

I'm trying to get data from three tables (photos, albums, album_photos),
then the program searches a user's albums in the album table, then look for every album the ID's of the photos in album_photos, and then, for each ID, look at the photos table all data by ID.
Yesterday I asked something like this: Inner join with 3 tables, but now, I think the question is different, I'm wondering how I can add a limit to a request by inner join.
So, I'm working now in this code:
SELECT a.album_name, a.album_id, c.*
FROM albums a
INNER JOIN album_photos b ON a.album_id = b.album_id
INNER JOIN photos c ON b.photo_id = c.photo_id
WHERE (
SELECT COUNT(*)
FROM album_photos d
WHERE b.album_id = d.album_id
AND d.nick = :nick
) <=5
Ok, this code select's the albums that have 5 or less photos. I do not want the code to do that, no matter how many photos have the album, I want to show the album with a LIMIT OF 5 photos.
Other people have told me that you can not do it, I believe that this is not so, because the SQL language is very complex and I think we should have the tool to do it.
Is there any way to do this in a proper way?
*In the link that I'm shared above I put an example about the output data.
Try changing the where clause to this:
WHERE (
SELECT COUNT(*)
FROM album_photos d
WHERE d.album_id = b.album_id and
d.photo_id <= b.photo_id
AND d.nick = :nick
) <= 5
This counts the number of photos in order, not just the number of photos in the album.
Since album_photos has a mapping relationship between photos and albumns, you can specify the number of photos to join on by using TOP:
SELECT a.album_name, a.album_id, p.*
FROM albums a
INNER JOIN album_photos ap ON
ap.photo_id = (select top 5 photo_id from album_photos where a.album_id = ap.album_id order by photo_id)
INNER JOIN photos p ON ap.photo_id = p.photo_id
The Order by photo_id in the subquery will ensure the same 5 (or fewer) photos are returned
EDIT PER COMMENT. Modifying to use MySql LIMIT instead of T-SQL TOP
SELECT a.album_name, a.album_id, p.*
FROM albums a
INNER JOIN album_photos ap ON
ap.photo_id = (select photo_id from album_photos where a.album_id = ap.album_id order by photo_id LIMIT 0, 5)
INNER JOIN photos p ON ap.photo_id = p.photo_id

Query Topics & Categories from multiple tables

I'm having an issue with MySQL. I have two tables, categories and topics. I want to select all of the categories and join topics where categories.id equals the max topics.id where topics.cat_id equals categories.id. Basically I am trying to show a list of categories and then the most recent topic under that category.
Here is my select statement so far:
SELECT
*
FROM
categories
LEFT JOIN
topics
ON
categories.cat_id = (SELECT
MAX(topics.id), topic_cat
FROM
topics
WHERE
topic_cat = categories.cat_id)
GROUP BY
categories.cat_id
How can I efficiently do that? I'm getting an error "Operand should contain 1 column(s)".
You should consider updating your select clause to only pull the columns you need from both tables (there will likely be duplicate columns with *), but give this a shot:
select *
from categories c
left join topics t
on c.cat_id = t.topic_cat
and t.id = (select MAX(id) from topics where topic_cat = c.cat_id)

2 LEFT JOINS count in a query

I have a download-component and want the categories to display the subcats and item count in advance. 1 of both works, but when trying to get both, the result is the multiply of both.
The code I use:
SELECT a.*,
count(b.parentid) AS catscount,
count(c.id) AS itemscount
FROM (jos_foc_downl_categories AS a LEFT JOIN jos_foc_downl_items AS c ON c.catid = a.id )
LEFT JOIN jos_foc_downl_categories AS b ON b.parentid = a.id
WHERE a.parentid=0
GROUP BY a.id
This results for a category with 4 subcategories and 5 files in the number 20 for catscount and 20 for itemscount.
What's wrong with this? Thanks!
You're counting all rows, including duplicated values. Use DISTINCT to only count each distinct value once:
SELECT a.*,
count(DISTINCT b.parentid) AS catscount,
count(DISTINCT c.id) AS itemscount
....