Reputation: 702
I've seen similar questions posted on here, but none of the solutions I've found have seemed to give me the results I'm looking for.
So I have two tables:
Cards table has collectible cards with unique IDs and additional metadata (casting cost, etc.):
Cards
| id INTEGER | name TEXT | ... |
Prints table contains printing information for cards from Cards table (this is because the same card can be printed in different versions through different card sets):
Prints
| id INTEGER | card_id INTEGER | set TEXT | ... |
What I would like to do is to be able to query for a given card, but include all printings for said card within a single row response. I've been able to do that, somewhat, but instead if there are 6 printings for a card it will result in 6 rows, each row containing all the printing information as a string in JSON format.
The query I've been trying to use is the following:
SELECT DISTINCT(cards.id), cards.*, array_agg(printings.*) FROM cards
LEFT JOIN printings ON cards.id=printings.card_id
WHERE cards.name="C1"
GROUP BY cards.id,printings.id ORDER BY cards.id;
This has resulted in output like (and the printing_information was just a string):
| id | name | ... | printing_information |
| 1 | C1 | ... | { printInfo1, printInfo2, printInfo3 } |
| 1 | C1 | ... | { printInfo1, printInfo2, printInfo3 } |
| 1 | C1 | ... | { printInfo1, printInfo2, printInfo3 } |
| 1 | C1 | ... | { printInfo1, printInfo2, printInfo3 } |
| 1 | C1 | ... | { printInfo1, printInfo2, printInfo3 } |
| 1 | C1 | ... | { printInfo1, printInfo2, printInfo3 } |
What I would like to be able to do is join the prints with the cards such that the response would produce:
| id | name | ... | printing_information |
| 1 | C1 | ... | { print1Info, print2Info, print3Info } |
| 2 | C2 | ... | { print1Info, print2Info } |
Is it worth doing all of this in a single query? I could achieve this with some minor post processing, but would that be as performant as it would require multiple queries and would not be that pretty since it could be for multiple cards and search for multiple ids seems messy.
Any help would be appreciated!
Upvotes: 1
Views: 482
Reputation:
You need to aggregate the prints
table first, then join to the cards
table.
SELECT c.*, p.printing_information
FROM cards c
LEFT JOIN (
select pr.card_id, jsonb_agg(to_jsonb(pr)) as printing_information
from printings pr
group by pr.card_id
) p ON c.id = p.card_id
WHERE c.name = 'C1'
ORDER BY c.id;
to_jsonb(pr)
converts the whole row from the printings
table into a JSON value. This is then aggregated into a JSON array using jsonb_agg()
for all printings of a card. If you want to remove some columns from the JSON, e.g. the card_id
and 'id' columns from the JSON, you can use to_jsonb(pr) - 'card_id' - 'id'
Upvotes: 2