I'm trying to extract transaction details from two already existing tables:
transactions
, containing the total amount received,bills
, with a row for each bill received in the transaction, and containing the denomination of the bill.
Both are indexed with a common session
id. [Correction: only the transactions
table is indexed on session
id.]
I've joined the tables and made subqueries to count the number of each bill denomination per transaction (how many 10s, 20s, etc.). I want to get one record for each transaction with all the counts on the same row.
I made it as far as this query:
SELECT
t.session,
to_char(t.amount::numeric, '"$"9990D99') AS "USD",
(select count(b.denom) where b.denom = '50' ) AS "50",
(select count(b.denom) where b.denom = '20') AS "20",
(select count(b.denom) where b.denom = '10') AS "10",
(select count(b.denom) where b.denom = '5') AS "5",
(select count(b.denom) where b.denom = '1') AS "1"
FROM transactions AS t JOIN bills AS b USING (session)
GROUP BY
t.session, t.amount, b.denom
ORDER BY
t.session,
b.denom ASC;
... which correctly gives me the bill counts, but with one row for each denomination:
session | USD | 50 | 20 | 10 | 5 | 1
--------------+-----------+----+----+----+---+----
c64af32f1815 | $ 135.00 | | | | 1 |
c64af32f1815 | $ 135.00 | | | 1 | |
c64af32f1815 | $ 135.00 | | 6 | | |
643e096b6542 | $ 175.00 | | | | | 10
643e096b6542 | $ 175.00 | | | | 1 |
643e096b6542 | $ 175.00 | | 8 | | |
ce7d2c647eff | $ 200.00 | 4 | | | |
What I want is this, with one row per transaction:
session | USD | 50 | 20 | 10 | 5 | 1
--------------+-----------+----+----+----+---+----
c64af32f1815 | $ 135.00 | | 6 | 1 | 1 |
643e096b6542 | $ 175.00 | | 8 | | 1 | 10
ce7d2c647eff | $ 200.00 | 4 | | | |
What do I need to understand to fix this query?
Revised Query (following @erwin suggestion to avoid subqueries):
SELECT
t.session,
to_char(t.amount::numeric, '"$"9990D99') AS "USD",
COUNT(NULLIF(b.denom = '100', FALSE)) AS "100",
COUNT(NULLIF(b.denom = '50', FALSE)) AS "50",
COUNT(NULLIF(b.denom = '20', FALSE)) AS "20",
COUNT(NULLIF(b.denom = '10', FALSE)) AS "10",
COUNT(NULLIF(b.denom = '5', FALSE)) AS "5",
COUNT(NULLIF(b.denom = '1', FALSE)) AS "1"
FROM transactions AS t JOIN bills AS b USING (session)
GROUP BY
t.session, t.amount, b.denom
ORDER BY
t.session,
b.denom ASC;
This query still generates one line of output for each aggregate (count) function call.