sergio
Doing a postgresql coalesce with custom type in Ecto
I’m trying to find the total amount of winnings for a specific backer in my database.
query =
from b in Gaming.Stakes.Backer,
left_join: bwt in assoc(b, :wallet_transactions),
left_join: bpwt in assoc(b, :backer_promotional_wallet_transactions),
where: b.id == ^backer.id,
where: bwt.type == "winnings" or bpwt.type == "winnings",
group_by: b.id
from e in subquery(query),
select: [e.backer_id, e.wallet_sums + e.promotional_wallet_sums]
I’m a bit stuck on how to do the coalesce, and the nested select. Ultimately what I need a single value to come back from the database.
This is the raw SQL query that works as intended and give me the data I need. I’m trying to get this into Ecto code.
SELECT
backer_id,
wallet_sums + promotional_wallet_sums AS total
FROM
(
SELECT
backers.id AS backer_id,
SUM( COALESCE( wallet_transactions.amount,
(
'USD',
0
)
:: money_with_currency ) ) AS wallet_sums,
SUM( COALESCE( promotional_wallet_transactions.amount,
(
'USD',
0
)
:: money_with_currency ) ) AS promotional_wallet_sums
FROM
backers
LEFT JOIN
backer_wallet_transactions
ON backer_wallet_transactions.backer_id = backers.id
LEFT JOIN
wallet_transactions
ON wallet_transactions.id = backer_wallet_transactions.wallet_transaction_id
LEFT JOIN
backer_promotional_wallet_transactions
ON backer_promotional_wallet_transactions.backer_id = backers.id
LEFT JOIN
promotional_wallet_transactions
ON promotional_wallet_transactions.id = baker_promotional_wallet_transactions.promotional_wallet_transaction_id
WHERE
backers.id = 'c9ffd955-3333-3333-3333-578346b33333'
AND
(
wallet_transactions.type = 'winnings'
OR promotional_wallet_transactions.type = 'winnings'
)
GROUP BY
backers.id
)
sums
Marked As Solved
sergio
I managed to figure it out.
The tricky part was to use the ? fragment to reference the relationship because of it’s indirect in sql -vs- direct in ecto relationship magic nature.
query =
from b in Gaming.Stakes.Backer,
left_join: wt in assoc(b, :wallet_transactions),
left_join: pwt in assoc(b, :promotional_wallet_transactions),
where: b.id == ^backer.id,
where: wt.type == ^"winnings" or pwt.type == ^"winnings",
group_by: b.id,
select: %{
backer_id: b.id,
wallet_sums:
fragment(
"""
SUM( COALESCE( ?.amount,
(
'USD',
0
)
:: money_with_currency ) )
""",
wt
),
promotional_wallet_sums:
fragment(
"""
SUM( COALESCE( ?.amount,
(
'USD',
0
)
:: money_with_currency ) )
""",
pwt
)
}
query =
from e in subquery(query),
select: e.wallet_sums + e.promotional_wallet_sums
Repo.one(query)
Also Liked
LostKobrakai
In my opinion sum for money should work exactly as sum works on numeric/decimal columns would, granted all currencies are the same. Any different behavior should be a custom and separately documented aggregation function.
kip
Do I understand correctly that the intent is to sum :money_with_currency amounts, but treat NULL amounts as 0 amounts in the currently aggregating currency (USD for your example?). That might be possible and reasonable to implement as an additional aggregate function and I’ll take a look (I’m the author of ex_money which it appears you may be using).
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









