TIL how to use snowflake's VALUES sub-clause

⋅ 2 minute read


Today I found out about the useful VALUES() sub-clause in snowflake that allows you to dynamically generate a fixed, known set of rows inside your query.

Problem

I had a table exchange_rates of EUR-currency pairs with their corresponding exchange rates

date base_currency target_currency exchange_rate
2023-10-03 ‘EUR’ ‘GBP’ 0.87
2023-10-03 ‘EUR’ ‘USD’ 1.05
2023-10-03 ‘EUR’ ‘JPY’ 155.95

that I wanted to join with a table transactions which contained transaction prices in different currencies:

id price price_currency
1 100.53 ‘GBP’
2 1021.68 ‘EUR’
3 7.99 ‘JPY’

My goal was to standardize all prices to EUR.

The SQL query to join the two tables would be:

select 
id,
price,
price_currency,
exchange_rate
from transactions as t
inner join exchange_rates as er on er.target_currency = t.price_currency

The issue was that exchange_rates did not have a EUR-EUR currency pair and I didn’t have access to the data source. So, the inner join would filter out all EUR transactions (or leave NULLs in case of a left join). This is a bit of a constructed problem to show an application of VALUES(). One could alternatively fill the NULLs with 1.0s after a left join.

Solution

I used snowflake’s VALUES() to dynamically generate another row in the query. I use this with a UNION statement to complete the exchange_rates table before joining:

with exchange_rates_complete as (
  select * from exchange_rates
  union
  select * from (values( '2023-10-03', 'EUR', 'EUR', 1.0, 1))
)

select 
id,
price,
price_currency,
exchange_rate
from transactions as t
inner join exchange_rates_complete as er on er.target_currency = t.price_currency

The joined table looks like this:

id price price_currency exchange_rate
1 100.53 ‘GBP’ 0.87
2 1021.68 ‘EUR’ 1.0
3 7.99 ‘JPY’ 155.95

If you have any thoughts, questions, or feedback about this post, I would love to hear it. Please reach out to me via email.

Tags:
#snowflake   #sql  

Related: