I have table transaction and transactionaction with the following columns. transactionid in transactionaction is a foreign key to transaction.
| transactionid | name |
|---|---|
| 1 | Trans 1 |
| 2 | Trans 2 |
| 3 | Trans 3 |
| 4 | Trans 4 |
| actionid | transactionid | actiontype | value |
|---|---|---|---|
| 1 | 1 | 1 | null |
| 2 | 1 | 2 | null |
| 3 | 1 | 3 | null |
| 4 | 2 | 1 | 1 |
| 5 | 2 | 2 | null |
| 6 | 2 | 3 | null |
I need to find every transaction with contains all actions passed by user. It's important to note that some actions can be filtered only based on actionType (actions 2, 3) and some also on value (action 1). So if user wants to find transaction with actions 2,3 he should get transaction 1 and 2. For this case, with help of this answer https://stackoverflow.com/a/41140629/12035106, I created this query.
SELECT * from transaction
WHERE transactionid in (
SELECT transactionid
FROM public.transactionaction
group by transactionid
having array_agg(actiontype) @> array[2,3]
)
However, action 1 need to take value into consideration because action 1 with value == null is different than action with value != null. In this case, I cannot really use the previous query. I came up with this query.
SELECT * from transaction
WHERE transactionid in (
SELECT transactionid
FROM public.transactionaction
group by transactionid
having array_agg(actiontype) @> array[2,3]
) AND transactionid in (
SELECT transactionid
FROM public.transactionaction
WHERE actiontype = 1 AND value is not null
)
This one work, as a result, I will get only transaction 2, but I feel I overcomplicated it because this query is looping through the same table multiple times. I created an index on actiontype, so the query plan looks better, but maybe there is an easier way to achieve the same result?