using LIMIT and ORDER BY with LEFT JOIN in sql query - php

I'm a bit new to JOIN and I'm finding it difficult to understand how I can query one table with ORDER BY and LIMIT and using only ORDER BY on my JOINED 'right' table I think it is? So Basically if I was to query the two tables individually I would use these queries:
SELECT * FROM posts ORDER BY dateSubmitted DESC LIMIT ?,5
'?' standing for my bind_param() because I'm creating a pagination. Now for my 'right' Second table:
SELECT * FROM postcomments WHERE postcomments.postID = posts.ID ORDER BY dateSubmitted DESC
As far as my understanding goes to 'link' the two tables together I want to be using LEFT JOIN so that I will receive all my data from the 'left' table (being posts).
SELECT * FROM posts LEFT JOIN postcomments ON postcomments.postID = posts.ID
Now I can do this but I'm unsure where I would but my ORDER BY and LIMIT for both tables?
I've seen several different ways and I think this is what's getting me confused like I've seen this:
SELECT p.* FROM posts p ORDER BY posts.dateSubmitted DESC LIMIT ?,5
LEFT JOIN (SELECT * FROM postcomments
WHERE postscomments.postID = p.ID ORDER BY postcomments.dateSubmitted);
But I'm really unsure how to structure my query :S Any help appreciated :)

It will be at the end like this:
Select * from
(SELECT * FROM posts ORDER BY dateSubmitted DESC LIMIT ?,5) as tempPost
LEFT JOIN postcomments on (postscomments.postID = tempPost.ID)

Related

left join alle topics only last post order by sticky and last post DESC

i am trying to get all topics based on a forum ID.
Those topics need to be ordered by sticky first and then by last post date secondly.
I have this query, working almost fine but it doesn't order the topics in the way i want.
SELECT
forum_posts.posted_by,
forum_posts.posted,
forum_topics.id,
forum_topics.subject,
forum_topics.sticky,
forum_topics.closed
FROM
forum_posts
LEFT JOIN
forum_topics
ON
forum_topics.id=forum_posts.topic_id
WHERE forum_topics.forum_id=$forumdata->id
GROUP BY forum_topics.id
ORDER BY forum_posts.posted DESC
If I read your question correctly, then you only need to make a slight change to the ORDER BY clause:
ORDER BY
forum_topics.sticky, -- just add this
forum_posts.posted DESC;
However, as you are selecting non aggregate columns, my hunch is that you should really be using a subquery to figure out the latest post:
SELECT
ft.*, fp1.*
FROM forum_posts fp1
INNER JOIN
(
SELECT topic_id, MAX(posted) AS max_posted
FROM forum_posts
GROUP BY topic_id
) fp2
ON fp1.topic_id = fp2.topic_id AND
fp1.posted = fp2.max_posted
LEFT JOIN forum_topics ft
ON fp1.id = ft.topic_id
ORDER BY
ft.sticky;
if you need sticky first an then post then you need order by orum_topics.sticky, forum_posts.posted eg:
SELECT
forum_posts.posted_by,
forum_posts.posted,
forum_topics.id,
forum_topics.subject,
forum_topics.sticky,
forum_topics.closed
FROM
forum_posts
LEFT JOIN
forum_topics
ON
forum_topics.id=forum_posts.topic_id
WHERE forum_topics.forum_id=$forumdata->id
GROUP BY forum_topics.id
ORDER BY forum_topics.sticky DESC, forum_posts.posted DESC

select only one column distinct mysql

I have 3 tables - users, journals, journaltags. I select data from 3 tables using chosen tags.
$sqltheme="SELECT users.id as uid, users.name, users.surname, users.avatar, journals.id, journals.author_id, journals.title, journals.text, journals.create_date, journaltags.name as jname FROM users
INNER JOIN journals ON users.id=journals.author_id
INNER JOIN journaltags ON journaltags.journal_id = journals.id WHERE journals.create_date LIKE ? AND journals.author_id=? AND (".$expression.") ORDER BY journals.id DESC LIMIT 10";
$stmtheme=$conn->prepare($sqltheme);
$stmtheme->execute($array);
But if two tags is the same for one journal then it is selected the same journal two times. How can I make DISTINCT journals.id. I tried GROUP BY journals.id but it didnt help.
If I understand correctly, your problem is that the journaltags table may have one or more rows with a duplicated journal_id and name column value, right?
You can simply add a distinct clause to your select statement, after the word SELECT:
SELECT DISTINCT users.id as uid, users.name, users.surname, users.avatar, journals.id, journals.author_id, journals.title, journals.text, journals.create_date, journaltags.name as jname FROM users
INNER JOIN journals ON users.id=journals.author_id
INNER JOIN journaltags ON journaltags.journal_id = journals.id WHERE journals.create_date LIKE ? AND journals.author_id=? AND (".$expression.") ORDER BY journals.id DESC LIMIT 10
The reason that your GROUP BY journals.id did not work, is because you had other columns that needed to be included in the grouping as well. Adding distinct is essentially a short way of writing group by [all selected columns]

MYSQL return rows with number of column relationships in another table

I have a table categories and table posts . I want to return categories that have more than 3 posts.
My query
SELECT `categories`.`category_title`, COUNT(posts.post_id) as total_posts
FROM (`categories`)
JOIN `posts` ON `posts`.`category_id` = `categories`.`category_id`
HAVING `total_posts` > 3
ORDER BY `categories`.`date_created` desc
it returns just 1 row.. What is the correct way to do this type of query without using 2 queries?
Your query is making use of a MySQL feature called "hidden columns" and you might not even know it. This is because your query is referencing elements, such as date_created, which should be aggregated but are not ("should" here means according to the SQL standard and most other databases).
The problem with your query is that it is missing the group by. An alternative way of writing this is with the aggregation in a subquery, before joining to category:
SELECT `categories`.`category_title`, total_posts
FROM `categories` JOIN
(select categoryid, COUNT(posts.post_id) as total_posts
from `posts`
group by categoryid
having count(*) > 3
) pc
ON `pc`.`category_id` = `categories`.`category_id`
ORDER BY `categories`.`date_created` desc
You need to group the items by category.
SELECT `categories`.`category_title`, COUNT(posts.post_id) as total_posts
FROM (`categories`)
JOIN `posts` ON `posts`.`category_id` = `categories`.`category_id`
GROUP BY `categories`.`category_id`
HAVING `total_posts` > 3
ORDER BY `categories`.`date_created` desc

mysql has all values

This is relating to my last question mysql query with AND, OR and NOT
Instead of editing the question, I am asking a new one because the question is only part of the previous question with an alteration.
I am looking to do a mysql query that returns me all articles that have all required topics.
Article
id
....
Topic
id
....
ArticleTopics
article_id
topic_id
type
something that would effectively do:
SELECT * FROM Article LEFT JOIN ArticleTopics ON Article.id = ArticleTopics.article_id
WHERE ArticleTopics.topic_id HAS ALL (these topics)
Is this possible? What is the best approach for this?
Several of the other answers suggest using aliases on the child table for each filter clause - this may not be very efficient or scale well.
Consider:
SELECT x.*
FROM Article x INNER JOIN
(SELECT t.article_id, COUNT(t.article_id)
FROM articleTopics t
WHERE t.topic_id IN ([your_list_of_topics])
GROUP BY t.article_id
HAVING COUNT(t.article_id)>=[number of elements in [your_list_of_topics]]
ORDER BY COUNT(t.article_id) DESC
LIMIT 0,100) AS ilv
ON x.id=ilv.article_id
Another advantage of this approach is that the structure of the query doesn't need to change with the number of topics you are searching for - you could even put them in a temporary table and perform a join instead of using the ' IN (...)' literal.
You'd need to try it out to see which query behaves better.
That is done using multiple joins with the same table.
To select all articles that have topics with ID 1, 2 and 3, you need to do:
SELECT * FROM Article a
INNER JOIN ArticleTopics at1 ON a.id = at1.article_id AND at1.topic_id = 1
INNER JOIN ArticleTopics at2 ON a.id = at2.article_id AND at2.topic_id = 2
INNER JOIN ArticleTopics at3 ON a.id = at3.article_id AND at3.topic_id = 3
// EDIT
Fixed it. Added table aliasses; I must have been working with good ORM solutions for too long...
SELECT
*
FROM
Article
WHERE
(SELECT COUNT(*) FROM ArticleTopics
WHERE Article.id = ArticleTopics.article_id AND
ArticleTopics.topic_id=1) > 0 AND
(SELECT COUNT(*) FROM ArticleTopics
WHERE Article.id = ArticleTopics.article_id AND
ArticleTopics.topic_id=2) > 0 AND
(SELECT COUNT(*) FROM ArticleTopics
WHERE Article.id = ArticleTopics.article_id AND
ArticleTopics.topic_id=3) > 0 AND
...

PHP/MySQL Query In a loop, how to append to just one query?

I have a query to pull all articles out of the database..
$get_articles = $db->query("
SELECT *, a.id AS id, s.type AS type FROM ".$prefix."articles a
LEFT JOIN ".$prefix."sources s ON (s.id = source_id)
WHERE a.type!='trashed' ORDER BY a.timestamp DESC LIMIT $start, $end");
Within the loop of this query, I do then do another query on the same table to find related articles to the 'title' of the article, stored as '$related_phrase'. The query within the loop is:
// get related articles to this entry
$get_related = $db->query("
SELECT *, a.id AS id, MATCH (title, description) AGAINST ('$related_phrase') AS score FROM ".$prefix."articles a
LEFT JOIN ".$prefix."sources s ON (s.id = source_id) WHERE a.type!='trashed' AND MATCH (title, description) AGAINST ('$related_phrase') AND a.id!='$articles[id]' HAVING score > 7
ORDER BY a.timestamp DESC LIMIT 0, 3");
This basically means we have a query in a loop which is causing the pages to load very slowly.
What we want to do, is bring the query from within the loop, in the main query, so it's all working within one query, if that's possible?
Any help very much appreciated!
I don't think you would gain much speed by merging the two queries.
One thing you could try is to get a list of all articles and DISTINCT searchphrases (in e.g. temptable), and then build a query to get all related articles in one single go. Lastly match up related articles with the article list.
try this:
$articles_and_related = $db->query("
SELECT *
FROM ".$prefix."articles art
LEFT JOIN (
SELECT * FROM ".$prefix."articles x
WHERE
score > 7
AND x.type != 'trashed'
AND x.id != art.id
AND MATCH(x.title, x.description) AGAINST (art.title)
LIMIT 3
) rel
LEFT JOIN ".$prefix."sources s2 ON (s2.id = rel.source_id)
LEFT JOIN ".$prefix."sources s ON (s.id = art.source_id)
WHERE
art.type!='trashed'
ORDER BY art.timestamp DESC LIMIT $start, $end");

Categories