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.
 
     
     
     
    