: greatest-n-per-group relational-division.
100 (person, card_provider), , , :
SELECT a.person
, a.balance AS amex_balance
, v.balance AS visa_balance
, a.timestamp AS amex_timestamp
, v.timestamp AS visa_timestamp
FROM persons p
CROSS JOIN LATERAL (
SELECT balance, timestamp
FROM credit_card_balances
WHERE person = p.id
AND card_provider = 'amex'
ORDER BY timestamp DESC
LIMIT 1
) a
JOIN LATERAL (
SELECT balance, timestamp
FROM credit_card_balances
WHERE person = p.id
AND card_provider = 'visa'
ORDER BY timestamp DESC
LIMIT 1
) v ON v.balance > a.balance;
. :
CREATE INDEX ON credit_card_balances (person, card_provider, timestamp DESC, balance);
balance , .
, timestamp NOT NULL, NULLS LAST .
:
(person, card_provider) DISTINCT ON . persons . .
.
DISTINCT ON , LATERAL :
SELECT a.person
, a.balance AS amex_balance
, v.balance AS visa_balance
, a.timestamp AS amex_timestamp
, v.timestamp AS visa_timestamp
FROM (
SELECT DISTINCT ON (person)
person, balance, timestamp
FROM credit_card_balances
WHERE card_provider = 'amex'
ORDER BY person, timestamp DESC
) a
JOIN LATERAL (
SELECT balance, timestamp
FROM credit_card_balances
WHERE card_provider = 'visa'
AND person = a.person
ORDER BY timestamp DESC
LIMIT 1
) v ON v.balance > a.balance
DISTINCT ON , :
SELECT a.person
, a.balance AS amex_balance
, v.balance AS visa_balance
, a.timestamp AS amex_timestamp
, v.timestamp AS visa_timestamp
FROM (
SELECT DISTINCT ON (person)
person, balance, timestamp
FROM credit_card_balances
WHERE card_provider = 'amex'
ORDER BY person, timestamp DESC
) a
JOIN (
SELECT DISTINCT ON (person)
person, balance, timestamp
FROM credit_card_balances
WHERE card_provider = 'visa'
ORDER BY person, timestamp DESC
) v USING (person)
WHERE v.balance > a.balance;
: DISTINCT ON , HAVING:
SELECT person
, max(balance) FILTER (WHERE card_provider = 'amex') AS amex_balance
, max(balance) FILTER (WHERE card_provider = 'visa') AS visa_balance
, max(timestamp) FILTER (WHERE card_provider = 'amex') AS amex_timestamp
, max(timestamp) FILTER (WHERE card_provider = 'visa') AS visa_timestamp
FROM (
SELECT DISTINCT ON (person, card_provider)
person, card_provider, balance, timestamp
FROM credit_card_balances
WHERE card_provider IN ('amex', 'visa')
ORDER BY person, card_provider, timestamp DESC
) c
GROUP BY person
HAVING max(balance) FILTER (WHERE card_provider = 'visa')
> max(balance) FILTER (WHERE card_provider = 'amex');
FILTER Postgres 9.4 +: