I have a query where I want to fetch columns from two tables (a parent and reference table), as well as select total number of categories of each post on the reference table
articles
id
title
poster
pdate
content
categories
id
name
cats_rel (Relationship table with Foreign Key constraints)
id
pid
cat_id
I want to fetch list of posts with one category id and total number of categories for each post.
I use this to fetch the required data, but it is slow. Is there a better way to get it faster?
SELECT cc.id, title, poster, pdate, content, js.pid, js.sno
FROM articles cc LEFT JOIN
(SELECT pid, cat_id, count(cat_id) as sno FROM cats_rel GROUP BY pid)js
ON js.pid = cc.id WHERE cc.status='approved' ORDER BY cc.id DESC
You don't need a inner query.
SELECT cc.id, title, poster, pdate, content, js.pid, count(js.cat_id) as sno
FROM articles wp
LEFT JOIN cats_rel js ON js.pid = cc.id
WHERE wp.status='approved'
group by cc.id, title, poster, pdate, content, js.pid
ORDER BY cc.id DESC
I would rewrite the query using a correlated subquery
SELECT cc.id, cc.title, cc.poster, cc.pdate, cc.content,
(SELECT COUNT(*)
FROM cats_rel js
WHERE js.pid = cc.id
) as sno
FROM articles cc
WHERE cc.status = 'approved'
ORDER BY cc.id DESC;
(It seems that js.pid is redundant in the select list.)
For this query, you want two indexes: articles(status, id desc) and cats_rel(pid).
Related
I have tables: post & votes
i want to sort the posts in table 'post' by count of column in table 'votes'.
SELECT * FROM post ORDER BY <SELECT count(*) as c FROM votes WHERE post = $row[srno]>
The 'votes' table contains 2 columns: post and user; It is meant to store votes of each post that exists in 'post' table.
SELECT count(*) as c FROM votes WHERE post = $row[srno]
Above query gives me the no. of votes of the specified post. How do i sort posts by this count?
You can use a JOIN for that:
SELECT p.*, COUNT(*) as vcount
FROM post p
JOIN votes v ON v.post = p.srno
GROUP BY p.*
ORDER BY vcount
This will also add a column vcount to the table that contains the number of votes.
Note that this query will sort in ascending order so lowest number of votes first. You can use DESC to sort in descending order (so highest number of votes first):
SELECT p.*, COUNT(*) as vcount
FROM post p
JOIN votes v ON v.post = p.srno
GROUP BY p.*
ORDER BY vcount DESC
Maybe you can all have from one table, votes:
SELECT COUNT(post) as c, post
FROM votes
GROUP BY Country
ORDER BY post ASC;
How to query multiple tables using different constraints?
For example, limiting results to 1 row from the first table, but getting all results from the second and then ordering those results by unique id ASC.
For example, something like this:
SELECT p.entry_id AS post_id,
p.topic AS post_topic,
p.body AS post_body,
r.reply AS post_reply
FROM
#should get only one row
(SELECT entry_id, topic, body FROM entry_posts WHERE entry_id = {$id} LIMIT 1) AS p
FULL JOIN
#should get all rows with this entry_id and order them
(SELECT reply, FROM entry_replies WHERE entry_id = {$id} ORDER BY id ASC) AS r
ON p.entry_id = r.entry_id
In this case both tables have a column called entry_id that contain the same values.
SELECT p.entry_id AS post_id,
p.topic AS post_topic,
p.body AS post_body,
r.reply AS post_reply
FROM entry_posts p
LEFT OUTER JOIN entry_replies r ON r.entry_id = p.entry_id
WHERE p.entry_id = {$id}
ORDER BY r.id
I'm making a blog. I have 2 tables, one for posts and the other for categories.
I want to display the category name, category date and the number of posts in each category. I have problems to display the number of posts in each category.
In posts table I have a column called cat_id which is equal to category.id
I have these 2 MySQL queries:
mysql_query("select Count(posts.id) as NumberOfPosts, cat_id from posts group by cat_id");
And
mysql_query("select name, date from categories");
I don't know how to have combine these two queries into one query. I'm using PHP.
You could use a join:
SELECT name, date, NumberOfPosts
FROM categories c
JOIN (SELECT cat_id, COUNT(*) AS NumberOfPosts
FROM posts
GROUP BY cat_id) p ON c.id = p.cat_id
EDIT:
To include categories with no posts, you could use a left join instead of regular join. You just need to handle the nulls you'd get for NumberOfPosts, e.g., by using coalesce:
SELECT name, date, COALESCE(NumberOfPosts, 0) AS NumberOfPosts
FROM categories c
LEFT JOIN (SELECT cat_id, COUNT(*) AS NumberOfPosts
FROM posts
GROUP BY cat_id) p ON c.id = p.cat_id
Right now I'm using UNION to get records from multiple tables, which is fine. But I want to include the author for the specific post.
$run = mysql_query("
SELECT article_id AS id, title, smalldesc, hits, coverpic AS picture, timestamp, member_id AS mid, type FROM articles
UNION
SELECT video_id AS id, titel, smalldesc, hits, ytid AS picture, timestamp, member_id AS mid, type FROM videos
UNION
SELECT picture_id AS id, title, smalldesc, hits, coverpic AS picture, timestamp, member_id AS mid, type FROM pictures ORDER BY timestamp DESC LIMIT ".$postnumbers." OFFSET ".$offset."
") or die(mysql_error());
I want the following select to be a part of the code above:
SELECT member_id, picture, fname, lname FROM members WHERE member_id='mid'
I want to get the member from each post, so I can print out who made the post.
You've got, as you asked, to join the members table to the three part queries of the UNION:
SELECT
a.article_id AS id,
a.title,
a.smalldesc,
a.hits,
a.coverpic AS picture,
a.timestamp,
a.member_id AS mid,
a.type,
m.picture,
m.fname,
m.lname
FROM
articles a
INNER JOIN
members m
ON
a.member_id = m.member_id
UNION
SELECT
v.video_id,
v.titel,
v.smalldesc,
v.hits,
v.ytid AS picture,
v.timestamp,
v.member_id AS mid,
v.type
m2.picture,
m2.fname,
m2.lname
FROM
videos v
INNER JOIN
members m2
ON
v.member_id = m2.member_id
UNION
...
to get this information.
I have two tables called 'events' and 'topics' each table can have many comments.
What I need to do is list all the events and topics with the amount of comments for each row. I've managed to return all the topics, which works great but I don't know how I can add the events table to the MySql. The comments and events table fields are listed below. Can anyone help me with this query?
Events:
ID
Event_Name
Comments:
post_id <-- the releated id for either the events or topics table
table <-- The table that the row belongs to so either topics or events
SELECT
t.id, t.title, c.created_at,
IF(ISNULL(c.allComments), 0, c.allComments) AS totalComments
FROM topics AS t
LEFT OUTER JOIN (
SELECT created_at, post_id, COUNT(*) AS allComments
FROM comments
GROUP BY post_id
) AS c ON c.post_id = t.id
ORDER BY tc.created_at DESC, c.allComments DESC
Sounds like events and topics should be the same table.
Still, I think we can do this with a UNION. Events and Topics have the same columns i hope? (Or at least the same important ones?)
(SELECT c.table as event_or_topic, e.*, count(C.table), MAX(C.created_at) as latest_c
FROM events E LEFT JOIN comments C on (C.post_id = E.id)
WHERE C.table = 'Events'
GROUP BY C.post_id)
UNION
(SELECT c.table as event_or_topic, t.id*, count(C.table), MAX(C.created_at) as latest_c
FROM topics T LEFT JOIN comments C on (C.post_id = E.id)
WHERE C.table = 'Topics'
GROUP BY C.post_id)
ORDER BY latest_c
Notice that the ORDER BY applies to the whole UNION, not the individual SELECTs.
The use of LEFT JOIN should allow those rows without Comments to still show. I think the problem is that we have parts of our select dependent on comments (ie - C.table, ordering on last comment, etc). The count should be fine - will just be zero if there are no comments.
You might need to change the SELECT part slightly. I'd like to display C.table so you know whether a row is a topic or event, but im afraid it might screw up the count. Do you need anything from comments besides the count? You use some columns other than post_id and table in your query that you neglected to explain in your question.
You still have columns I don't know what they are, like Comment's zoneTable
Try this:
SELECT
t.id, t.title, c.created_at, COUNT(c.allComments) AS totalComments
FROM topics AS t LEFT JOIN comments c ON t.id=c.post_id
GROUP BY t.id ORDER BY tc.created_at DESC, c.allComments DESC
If I understand your question you have 3 tables:
-Events
-Topics
-Comments
If that is true something like this should extract all the data:
SELECT *
FROM events,topics
LEFT JOIN comments ON post_ID = ID
ORDER BY date DESC
Hope i'm along the right lines!
W.
I've got it working. If anyone knows of a better and an efficient way of doing this, then please let me know:
(SELECT t.id, t.title, tc.dateCreated AS commentDate,
IF(ISNULL(tc.allComments), 0, tc.allComments) AS totalComments,
t.LastActive as dateChanged
FROM Events AS t
LEFT OUTER JOIN (
SELECT MAX(created_at) AS dateCreated, post_id,
COUNT(*) AS allComments
FROM comments
GROUP BY post_id
) AS tc ON tc.post_id = t.id)
UNION
(SELECT t.id, t.title, tc.dateCreated AS commentDate,
IF(ISNULL(tc.allComments), 0, tc.allComments) AS totalComments,
t.LastActive as dateChanged
FROM topics AS t
LEFT OUTER JOIN (
SELECT MAX(created_at) AS dateCreated, post_id,
COUNT(*) AS allComments
FROM comments
GROUP BY post_id
) AS tc ON tc.post_id = t.id)
ORDER BY commentDate DESC, dateChanged DESC, totalComments DESC