SQL query: select five most commented posts from different blogs - sql

I have a following tables Blogs(id) and Posts(id, blog_id, comment_count)
I need to select five most commented posts from different blogs. It's quite easy to do with a function, but is it possible to do with some kind of basic SQL?
Here's the query in SQL Server dialect
select top 5 top_post.* from Blogs b
cross apply
(select top 1 * from Posts p
where p.blog_id = b.id
order by p.comment_count) top_post
order by top_post.comment_count

SELECT b.*, c.num_comments
FROM
(
SELECT TOP 5 blog_id, SUM(comment_count) as num_comments
FROM posts GROUP BY blog_id ORDER BY SUM(comment_count) DESC
)c
INNER JOIN Blogs b ON (b.id = c.blog_id)
UPDATE Hopefully it's what you need. It's not very fast though.
SELECT b.*, c.comment_count
FROM
(SELECT blog_id, comment_count ,
ROW_NUMBER() OVER(PARTITION by blog_id ORDER BY comment_count DESC) as rnum
FROM posts
)c
INNER JOIN Blogs b ON (b.id = c.blog_id)
WHERE c.rnum <=5;

As far as I know, there is no standard way to implement Select Top which is actually supported by the major dbms.
See the comparison of SQL dialects

Related

How to SELECT post entries to which latest comment were created with SQL?

I have tables post and comment that has foreign key(post_id) to post. I want to get 100 "bump ordered" post entries. The post entry to which latest comment entry was created comes first. My first attempt was:
SELECT * FROM post WHERE id IN
(
SELECT DISTINCT post_id FROM comment
ORDER BY created_time DESC
LIMIT 100
);
Returns:
ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
The 2nd attempt:
SELECT * FROM post WHERE id IN
(
SELECT post_id from
(SELECT DISTINCT(post_id), posted FROM comment) AS c
ORDER BY c.created_time DESC
LIMIT 100
);
No error this time but doesn't do what I want. How can I make SQL do what I want ?
If you are looking to select the 100 posts that have the most recent comments, you could use aggregation :
select p.id, p.title, p.author
from posts p
inner join comments c on c.post_id = p.id
group by p.id, p.title, p.author
order by max(c.created_at) desc
limit 100
With this technique, you need to enumerate all posts columns that you want to see in the resultset in the select clause and in the group by clause.
Another option is to pre-aggregate:
select p.*
from posts p
inner join (
select post_id, max(created_at) max_created_at
from comments
group by post_id
order by max(created_at) desc
limit 100
) c on c.post_id = p.id
order by c.max_created_at desc

Make single query for news with comment counter

I have two tables: news and comments.
I need to write a query for news content and comments count.
I've tried
SELECT
news.id, news.title, news.date, news.author_name, news.short_content,
COUNT(com.comment)
FROM
php_base.news
LEFT JOIN
php_base.comments AS com ON news.id = com.news_id
ORDER BY
date DESC
LIMIT 10
I guess there should be a lot of "AS". Anybody can help me? Thanks
You are missing a GROUP BY:
SELECT n.id, n.title, n.date, n.author_name, n.short_content,
COUNT(c.comment) as cnt
FROM php_base.news n LEFT JOIN
php_base.comments c
ON n.id = c.news_id
GROUP BY n.id, n.title, n.date, n.author_name, n.short_content,
ORDER BY n.date DESC LIMIT 10

correct select statement for multiple tables

I'm trying to get the latest 5 titles from 3 tables, I think I might be going wrong somewhere in my statement.
Here is my statement
SELECT * FROM news N, blog B, comments C WHERE active='1' ASC LIMIT 5
After FROM you can only set 1 table where the results will come from. Moreover if you use keyword ASC you should also say the field you order by try:
SELECT * FROM news WHERE active='1' order by 'fieldnew' ASC
UNION ALL
(SELECT * FROM blog WHERE active='1' order by 'fieldblog' ASC)
UNION ALL
(SELECT * FROM comments WHERE active='1' order by 'fieldcommnet' ASC)
You need to make a join on three tables provided !
in sql-server:
select top 5 * from
(
select * from News N inner join blog B on N.id=B.id inner join comments C on C.id=N.id
)x
order <something>

MYSQL top N rows from multiple table join

Like, there is top keyword in sql server 2005, how to select top 1 row in mysql if i have join on multiple table & want to retrieve extreme of each ID/column. Limit restricts the no. of row returns so it can't solve my problem.
SELECT v.*
FROM document d
OUTER APPLY
(
SELECT TOP 1 *
FROM version v
WHERE v.document = d.id
ORDER BY
v.revision DESC
) v
or
SELECT v.*
FROM document d
LEFT JOIN
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY v.id ORDER BY revision DESC)
FROM version
) v
ON v.document = d.id
AND v.rn = 1
The latter is more efficient if your documents usually have few revisions and you need to select all or almost all documents; the former is more efficient if the documents have many revisions or you need to select just a small subset of documents.
Update:
Sorry, didn't notice the question is about MySQL.
In MySQL, you do it this way:
SELECT *
FROM document d
LEFT JOIN
version v
ON v.id =
(
SELECT id
FROM version vi
WHERE vi.document = d.document
ORDER BY
vi.document DESC, vi.revision DESC, vi.id DESC
LIMIT 1
)
Create a composite index on version (document, revision, id) for this to work fast.
If I understand you correctly, top doesn't solve your problem either. top is exactly equivalent to limit. What you are looking for is aggregate functions, like max() or min() if you want the extremes. for example:
select link_id, max(column_a), min(column_b) from table_a a, table_b b
where a.link_id = b.link_id group by link_id

Oracle subquery does not see the variable from the outer block 2 levels up

I'd like to get in one query a post and the first comment associated with the post. Here is how I do it in PostgreSQL:
SELECT p.post_id,
(select * from
(select comment_body from comments where post_id = p.post_id
order by created_date asc) where rownum=1
) the_first_comment
FROM posts p
and it works fine.
However, in Oracle I'm getting an error ORA-00904 p.post_id: invalid identifier.
It seems to work fine for one subselect, but I cannot get the comment with only one due to the fact that I need to use rownum (no limit / offset in Oracle).
What am I doing wrong here?
No, Oracle doesn't correlate the subqueries nested more than one level deep (and neither does MySQL).
This is a well-known problem.
Use this:
SELECT p.post_id, c.*
FROM posts
JOIN (
SELECT c.*, ROW_NUMBER() OVER (PARTITION BY post_id ORDER BY created_date ASC) AS rn
FROM comments c
) c
ON c.post_id = p.post_id
AND rn = 1
If you need SQL that is platform-independent, this will work:
SELECT p.post_id
, c.comment_body
FROM posts p
, comments c
WHERE p.post_id = c.post_id
AND c.created_date IN
( SELECT MIN(c2.created_date)
FROM comments c2
WHERE c2.post_id = p.post_id
);
But it assumes that (post_id, created_date) is the primary key of comments. If it isn't, you're going to get more than one line posts that have comments with the same created_date.
Also, it is likely to be slower than the solution that uses analytics, given by Quassnoi.