correct select statement for multiple tables - sql

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>

Related

SQLite Random sub query result

I have 2 SQLite tables, table_a and table_b. Table A contains a list of categories and Table B contains a list of words.
I'm trying to get all categories from table_a and a random word from table_b for each category. The below query allows me to get 1 result per category that has the lowest id in table_b.
SELECT table_a.category_id, table_a.category, subQuery.word, subQuery.word_category, subQuery.word_id
FROM table_a,
(SELECT *
FROM table_b
GROUP BY category_id
HAVING MIN(word_id)
) subQuery
WHERE subQuery.category_id = table_a.category_id;
Is there a way to return 1 random result from table_b for each category in table_a instead of the value with the lowest id?
I'm not really having much luck finding an answer online. Any help would be appreciated.
You can use a window function to pick one row per category:
select
c.category_id, c.category,
w.word, w.word_category, w.word_id
from categories c
left join
(
select
word, word_category, word_id, category_id,
row_number() over (partition by category_id order by random()) as rn
from words
) w on w.category_id = c.category_id and w.rn = 1
order by c.category_id;
Demo: https://dbfiddle.uk/?rdbms=sqlite_3.27&fiddle=bbbe8541adf2d4f62883b2a1c36aaa41
Update
You say that the query does not work in SQLite 3.8. We can only suspect a bug here, because we see it works in SQLite 3.27.
Here is another approach that may work for you. I am selecting a random word ID with each category using a LIMIT subquery. Then I join the word data.
select c.category_id, c.category, w.word, w.word_category, w.word_id
from
(
select
c.category_id, c.category,
(
select word_id
from words w
where w.category_id = c.category_id
order by random()
limit 1
) as word_id
from categories c
) c
join words w on w.word_id = c.word_id
order by c.category_id;
Demo: https://dbfiddle.uk/?rdbms=sqlite_3.27&fiddle=7630068aa3ba71e70b7a6bddd83047dc

One query to return multiple rows for multiple values with limit

Assume you have database with author and book tables.
I want to get 10 most recent books for each author.
Normally it is N+1 SQL queries.
1 to get all authors: SELECT * FROM author -> N rows.
N to get their most recent books: SELECT * FROM book WHERE authorId=$1 ORDER BY releaseDate LIMIT=10.
I want to have only 1 instead of N queries, to get 10 most recent books for list of authors. ( maybe it does not make sense in case of performance / but I do not know )
Like this -> completely wrong, because it returns most recent books in table not per author SELECT * FROM book WHERE authorId = ANY($1) ORDER BY releaseDate DESC LIMIT 10
Is there a way to make SQL query to return most recent books for list of authors? Thanks.
You can try using row_number()
select * from
(
select *,row_number() over(partition by a.authorid order by releasedate desc) as rn
from author a join books b on a.authorid=b.authorid
)f where rn<=10
An alternative to window functions using lateral join:
select a.authorid, b.*
from author a
cross join lateral
(
select * from books
where books.authorid = a.authorid
order by releasedate desc
limit 10
) b;

oracle select from 2 table restrict from 1 table and order by another

I have book and recipient table. I want to select maximum 20 rows order by recipient table's membershipdate column. After I got it, i want to order it by book table's id column. I wrote that sql. Is there any way to do this with less code?
SELECT *
FROM ( SELECT *
FROM ( SELECT b.*
FROM book b
JOIN recipient r ON r.id = b.recipient_id
WHERE b.bookno = 115
ORDER BY r.membershipdate DESC
)
WHERE ROWNUM <= 20
)
ORDER BY ID DESC
You can remove one layer of select:
SELECT *
FROM (
SELECT b.*
FROM book b
JOIN recipient r ON r.id = b.recipient_id
WHERE b.bookno = 115
ORDER BY r.membershipdate DESC
)
WHERE ROWNUM <= 20
ORDER BY id DESC;
Selecting b.* isn't normally a good, idea, it's better to specify the columns you actually want, even if you do really want them all - to make sure you get them in the order you expect.
You can also look at the row_number() analytic function in place of rownum, but that will give you slightly more code - not that it should matter, the effectiveness and efficiency of the query it rather more important that its length.
Doesn't this work?
SELECT * FROM
(SELECT b.*
FROM book b
JOIN recipient r ON r.id = b.recipient_id
WHERE b.bookno = 115 ORDER BY r.membershipdate DESC
) WHERE ROWNUM <= 20
ORDER BY ID DESC
In oracle you can use ROW_NUMBER() function to reduce the code as you want -
and you can even mix your Order columns also.
select * from (
select b.*,row_number() over (order by r.membershipdate desc) cnt
from book b
JOIN recipient r ON r.id = b.recipient_id
WHERE b.bookno = 115
order by cnt,b.id desc
) where cnt<=20;

SQL query: select five most commented posts from different blogs

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

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