SQL command that spans across tables - sql

I have these tables (authors, quotes, tags, quotes_tags) and I'd like to make a single query for a list of random quotes with their appropriate author and and tags (many) information.
Here's what I have right now, but the tags are being squashed and returning only one. How would I go about query that returns this set of quotes with the tags returned as json or whatever convention that's appropriate?
SELECT *
FROM quotes
JOIN authors ON quotes.author_id = authors.id
JOIN tags ON tags.id = quotes.id
ORDER BY RANDOM()
LIMIT 50
I am getting the following:
author | quote | tags
---------------------
john | lorem | hey
brian | lorem | test
but I'd like the following:
author | quote | tags
-------------------------------
john | lorem | hey, another (or whatever convention for a list -- json?)
brian | lorem | test, one, two

In version 8.4 and later, you can use array_agg:
SELECT a.author, q.quote, array_agg(t.tags)
FROM quotes q
INNER JOIN authors a
ON q.author_id = a.id
INNER JOIN tags t
ON t.id = q.id
GROUP BY a.author, q.quote
ORDER BY RANDOM()

Related

SQL multipart messages in two tables. Doesn't work if second table is empty

I am working on a query that will fetch multipart messages from 2 tables. However, it only works IF there are multiple parts. If there is only a one part message then the the join condition won't be true anymore. How could I make it to work for both single and multipart messages?
Right now it fails if there is an entry in outbox and nothing in outbox_multipart.
My first table is "outbox" that looks like this.
TextDecoded | ID | CreatorID
Helllo, m.. | 123 | Martin
Yes, I wi.. | 124 | Martin
My second table is "outbox_multipart" that looks very similar.
TextDecoded | ID | SequencePosition
my name i.. | 123 | 2
s Martin. | 123 | 3
ll do tha.. | 124 | 2
t tomorrow. | 124 | 3
My query so far
SELECT
CONCAT(ob.TextDecoded,
GROUP_CONCAT(obm.TextDecoded
ORDER BY obm.SequencePosition ASC
SEPARATOR ''
)
) AS TextDecoded,
ob.ID,
ob.creatorID
FROM outbox AS ob
JOIN outbox_multipart AS obm ON obm.ID = ob.ID
GROUP BY
ob.ID,
ob.creatorID
Use a left join instead of an (implicit) inner join. Then, also use COALESCE on the TextDecoded alias to make sure that empty string (and not NULL) appears in the expected output.
SELECT
CONCAT(ob.TextDecoded,
COALESCE(GROUP_CONCAT(obm.TextDecoded
ORDER BY obm.SequencePosition
SEPARATOR ''), '')) AS TextDecoded,
ob.ID,
ob.creatorID
FROM outbox AS ob
LEFT JOIN outbox_multipart AS obm
ON obm.ID = ob.ID
GROUP BY
ob.ID,
ob.creatorID,
ob.TextDecoded;
Note: Strictly speaking, outbox.TextDecoded should also appear in the GROUP BY clause, since it is not an aggregate. I have made this change in the query.

Aliases for 2 joins on one table in Microsoft Access

I have a table that shows relationships between items and another table with the items themselves:
articles_to_articles
-------------------------
|articleID_1|articleID_2|
-------------------------
|12345 |67890 |
|23442 |343243 |
-------------------------
articles
-----------------------------------------------------
|article_id | article_name|lots | of | other | stuff|
-----------------------------------------------------
I am attempting to generate a file with that consists of the relationships from articles_to_articles but with the names in addition to the ids.
What I have so far is:
SELECT
a2a.articleID_1,
key_articles.article_name,
a2a.articleID_2,
val_articles.article_name
FROM
articles_to_articles a2a
INNER JOIN
articles key_articles
ON key_articles.articleID = articles_to_articles.articleID_1
INNER JOIN
articles val_articles
ON val_articles.articleID = articles_to_articles.articleID_2;
Access gives me a "missing operator" error but I can't seem to find the missing operator. What basic thing am I missing?
When joining more than two tables in MS Access, you must enclose each join within separate groups of parentheses, for example:
SELECT
a2a.articleID_1,
key_articles.article_name,
a2a.articleID_2,
val_articles.article_name
FROM
(
articles_to_articles a2a
INNER JOIN
articles key_articles
ON
key_articles.articleID = a2a.articleID_1
)
INNER JOIN
articles val_articles
ON
val_articles.articleID = a2a.articleID_2

PostgreSQL finding the 3 most popular articles in a news database

I'm currently trying to find the 3 most popular articles in a database. I want to print out the title and amount of views for each. I know I'll have to join two of the tables together (articles & log) in order to do so.
The articles table has a column of the titles, and one with a slug for the title.
The log table has a column of the paths in the format of /article/'slug'.
How would I join these two tables, filter out the path to compare to the slug column of the articles table, and use count to display the number of times it was viewed?
The correct query used was:
SELECT title, count(*) as views
FROM articles a, log l
WHERE a.slug=substring(l.path, 10)
GROUP BY title
ORDER BY views DESC
LIMIT 3;
If I understood you correctly you just need to join two tables based on one column using aggregation. The catch is that you can't compare them directly but have to use some string functions before.
Assuming a schema like this:
article
| title | slug |
-------------------
| title1 | myslug |
| title2 | myslug |
log
| path |
--------------------------
| /article/'myslug' |
| /article/'unmentioned' |
Try out something like the following:
select title, count(*) from article a join log l where concat('''', a.slug, '''') = substring(l.path, 10) group by title;
For more complex queries it can be helpful to at first write smaller queries which help you to figure out the whole query later. For example just check if the string functions return what you expect:
select substring(l.path, 10) from log l;
select concat('''', a.slug, '''') from article a;

Triple joins with SQL?

My database represents a library. Each book is tagged with multiple things, so that one title might be tagged 'science fiction', 'short stories', and 'Russian'.
There are three tables: books, tags, and books_tag_link. They look like this:
Books
ID | TITLE
-----------------------------
1 | Rendezvous With Rama
2 | Howl and Other Poems
3 | A Short History of Nearly Everything
Tags
ID | TAGNAME
-----------------------------
1 | science fiction
2 | fiction
3 | poetry
Books_Tag_Link
BOOK | TAG
-----------------------------------
1 | 1
1 | 2
2 | 3
Hopefully you can see how that would work. The books_tag_link table has two foreign keys, and links books to tags; each book has many tags, each tag is associated with many books. I don't know if this is the best way to do it but it's what the OSS library program Calibre does, and that's what I'm kind of using as a reference as I study.
Now what I want to do is say "select all fiction books". But I can't quite work out the proper way to express that thought in SQL. Select books.title where books.id = tags.id = books_tag_link.tag... or something. I'm not sure.
Can someone help me out with a tip or explanation of what I should be doing?
I'm using SQLite at the moment but MySQL-specific advice would be fine too.
SELECT b.title
FROM Books AS b
JOIN Books_Tag_Link AS bt ON b.id = bt.book
JOIN Tags AS t ON t.id = bt.tag
WHERE t.tagname = 'fiction'
Something like that?
select b.title
from Books b join Books_Tag_Link btl on btl.BOOK=b.ID
join Tags t on t.ID=btl.TAG
where t.TAGNAME='fiction';
Caveat: if all tables are large, you have to make sure that the fields mentioned in JOIN are keys (indexes).
You need to use two joins:
select
books.title
from
books
inner join
books_tag_link on
books_tag_link.book = book.id
inner join
tags on
tags.id = books_tag_link.tag
where
tag.tagname = 'fiction'

SQL Order by posts containing occurences of string in another table

So I have a table full of tag keywords.
Tags
------------------
asp
sql
html
and a table full of posts
posts
------------------
I really like ASP
This week with stuff about ASP
This post contains SQL
I want to display the top 10 tags in order of most unique posts containing occurrences in the posts table.
This is what I have but it is rubbish, I am ashamed.
SELECT Tag,(SELECT Count(*) FROM Posts WHERE post LIKE '%Tags.Tag%') As Mentions FROM Tags ORDER BY Mentions DESC
Please help! I know there is some sort of mystical UNION or GROUP BY I am missing here.
SELECT TOP 10 *
FROM (
SELECT tag,COUNT(tag) AS Total
FROM tags t
JOIN posts p ON p.post LIKE '%' + t.tag + '%'
GROUP BY tags
) totals
ORDER BY Total Desc
Tested in MySQL:
SELECT tag,count(*) AS n
FROM tags
JOIN posts ON post LIKE CONCAT("%",tag,"%")
GROUP BY tag
ORDER BY n DESC
LIMIT 10
To illustrate how this works, it is instructive to run first without the GROUP BY
SELECT tag,post
FROM tags
JOIN posts ON post LIKE CONCAT("%",tag,"%");
+------+------------------------+
| tag | post |
+------+------------------------+
| asp | I really like asp |
| asp | this week: asp |
| sql | this post contains sql |
+------+------------------------+
3 rows in set (0.00 sec)