ํ ์ด๋ธ ํ์ SQL UDF(UDTF)ยถ
Snowflake๋ 0๊ฐ, 1๊ฐ ๋๋ ์ฌ๋ฌ ๊ฐ์ ํ(๊ฐ๊ฐ 1๊ฐ ์ด์์ ์ด ํฌํจ)์ผ๋ก ๊ตฌ์ฑ๋ ํ ์ธํธ๋ฅผ ๋ฐํํ๋ SQL UDF๋ฅผ ์ง์ํฉ๋๋ค. ์ด๋ฌํ UDF๋ฅผ ํ ์ด๋ธ ํ์ UDF, ํ ์ด๋ธ UDF ๋๋ ๊ฐ์ฅ ํํ๊ฒ๋ UDTF (์ฌ์ฉ์ ์ ์ ํ ์ด๋ธ ํจ์)๋ผ๊ณ ํฉ๋๋ค.
์ฟผ๋ฆฌ์ FROM ์ ์์ UDTF์ ์ก์ธ์คํ ์ ์์ต๋๋ค.
์ด ํญ๋ชฉ์ ๋ด์ฉ:
๊ตฌ๋ฌธยถ
CREATE OR REPLACE FUNCTION <name> ( [ <arguments> ] )
RETURNS TABLE ( <output_col_name> <output_col_type> [, <output_col_name> <output_col_type> ... ] )
AS '<sql_expression>'
SQL UDTF๋ฅผ ํฌํจํ ๋ชจ๋ UDF์ ์ผ๋ฐ ๊ตฌ๋ฌธ์ ๋ํ ์์ธํ ์ค๋ช ์ CREATE FUNCTION ์ ์ฐธ์กฐํ์ญ์์ค.
์ธ์ยถ
name
:์ด๋ ์๋ณ์ ์๊ตฌ ์ฌํญ ์ ์ค๋ช ๋ ๊ท์น์ ๋ฐ๋ฅด๋ ์ ํจํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๋ธ์ ํธ ์ด๋ฆ์ด์ด์ผ ํฉ๋๋ค.
arguments
:์ด๋ ์์ด์ด์ผ ํฉ๋๋ค(์: ์ด ์ด๋ฆ์ด๊ฑฐ๋, ๋ฆฌํฐ๋ด์ด๊ฑฐ๋, ๋จ์ผ ๊ฐ์ผ๋ก ํ๊ฐํ ์ ์๋ ์). ์ผ๋ฐ์ ์ผ๋ก ํจ์๋ ์ด ์ด๋ฆ์ธ ํ๋์ ์ธ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ฌ์ฉ์๋ ๋ ์ด์์ ๊ฐ(์: ๋ ์ด์์ ์ด ์ด๋ฆ ๋๋ ์ด ์ด๋ฆ ํ๋์ ๋ฆฌํฐ๋ด ๊ฐ ํ๋ ์ด์)์ ์ ๋ฌํ ์ ์์ต๋๋ค.
์์๋ฅผ ์ ๋ฌํ๊ฑฐ๋ ๊ฐ์ ์ ํ ์ ๋ฌํ์ง ์์ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ, ์ ๋ ฅ์ด ๋งค๋ฒ ๊ฐ์ผ๋ฉด ์ถ๋ ฅ์ด ๋งค๋ฒ ๊ฐ์ต๋๋ค.
RETURNS TABLE(...)
UDF๊ฐ ํ ์ด๋ธ์ ๋ฐํํด์ผ ํจ์ ์ง์ ํฉ๋๋ค. ๊ดํธ ์์ ๋ฐํ๋ ํ ์ด๋ธ์ ํฌํจํ ์ด์ ์ด๋ฆ-์ ํ ํ์ด๋ฅผ ์ง์ ํฉ๋๋ค(์๋ ์ค๋ช ์ ๋ฐ๋ฆ).
output_col_name
:๋ฐํ๋ ํ ์ด๋ธ์ ํฌํจํ ์ถ๋ ฅ ์ด์ ์ด๋ฆ์ ๋๋ค. ํ๋ ์ด์์ ์ถ๋ ฅ ์ด์ด ์์ด์ผ ํฉ๋๋ค.
output_col_type
:์ถ๋ ฅ ์ด์ ๋ฐ์ดํฐ ํ์ ์ ๋๋ค.
sql_expression
:๊ฐ๊ฐ ํ๋ ์ด์์ ์ด์ด ์๋ 0๊ฐ ๋๋ ๊ทธ ์ด์์ ํ์ ๊ฐ์ง ํ ์ด๋ธ์ ๋ฐํํ๋ ์ ํจํ SQL ์ ๋๋ ๋ฌธ์ ๋๋ค. ์ถ๋ ฅ์ RETURNS ์ ์ ์ง์ ๋ ์ ๋ฐ ๋ฐ์ดํฐ ํ์ ๊ณผ ์ผ์นํด์ผ ํฉ๋๋ค.
์ฌ์ฉ๋ฒ ๋ ธํธยถ
SQL UDTF์ ๋ณธ๋ฌธ(์ผ๋ช โ์ ์โ)์ SELECT ์์ด์ด์ผ ํฉ๋๋ค.
sql_expression
์ฃผ์์ ๊ตฌ๋ถ ๊ธฐํธ๋ ์ผ๋ฐ์ ์ผ๋ก ์์๋ฐ์ดํ์ด์ง๋ง, ํ ์์ ๋ฌ๋ฌ ๊ธฐํธ$$
๋ฅผ ๊ตฌ๋ถ ๊ธฐํธ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ซ๋ ๊ตฌ๋ถ ๊ธฐํธ๋ ์ฌ๋ ๊ตฌ๋ถ ๊ธฐํธ์ ์ผ์นํด์ผ ํฉ๋๋ค.sql_expression
์ ์์๋ฐ์ดํ๊ฐ ํฌํจ๋ ๊ฒฝ์ฐ, ํ ์์ ๋ฌ๋ฌ ๊ธฐํธ๊ฐ ํธ๋ฆฌํฉ๋๋ค. ํ ์์ ๋ฌ๋ฌ ๊ธฐํธ๋ฅผ ์ฌ์ฉํ๋ ์๋ ์๋์ ์ ์น์ ์ ํฌํจ๋์ด ์์ต๋๋ค.๊ตฌ๋ถ ๊ธฐํธ๊ฐ ์์๋ฐ์ดํ์ด๊ณ ๋ณธ๋ฌธ์ ์์๋ฐ์ดํ๊ฐ ํฌํจ๋ ๊ฒฝ์ฐ, ๋ฐฑ์ฌ๋์ ๋ฌธ์
\
๋ฅผ ์ด์ค์ผ์ดํ ๋ฌธ์๋ก ์ฌ์ฉํ์ฌ ๋ณธ๋ฌธ์์ ์์๋ฐ์ดํ๋ฅผ ์ด์ค์ผ์ดํํ ์ ์์ต๋๋ค. ์๋์ ์ ์น์ ์ ์๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.UDTF์ ์ ์๋ ์ด์ ์ผ๋ฐ ํ ์ด๋ธ ์ด์ ์ฌ์ฉํ ์ ์๋ ๋ชจ๋ ์์น์ ๋ํ๋ ์ ์์ต๋๋ค.
RETURNS ์ ์ ์ง์ ๋ ๋ฐํ ํ์์ ํ ์ด๋ธ ํ์ ๊ฒฐ๊ณผ์ ์๋ ์ด์ ์ด๋ฆ๊ณผ ํ์์ ๊ฒฐ์ ํ๋ฉฐ, ํจ์ ๋ณธ๋ฌธ์์ SELECT ๋ฌธ์ ํด๋น ์์น์ ์๋ ์์ ํ์๊ณผ ์ผ์นํด์ผ ํฉ๋๋ค.
UDTF๋ฅผ ํธ์ถํ ๋ TABLE ํค์๋ ๋ค์์ ์ค๋ ๊ดํธ ์์ UDTF ์ด๋ฆ๊ณผ ์ธ์๋ฅผ ํฌํจํด์ผ ํฉ๋๋ค. ์์ธํ ๋ด์ฉ์ SQL UDTF ํธ์ถํ๊ธฐ ์น์ ์ ์ฐธ์กฐํ์ญ์์ค.
์ฐธ๊ณ
ํ ์ด๋ธ ํ์ ํจ์(UDTF)์ ์ ๋ ฅ ์ธ์ 500๊ฐ, ์ถ๋ ฅ ์ด 500๊ฐ๋ก ์ ํ๋ฉ๋๋ค.
SQL UDTF ํธ์ถํ๊ธฐยถ
์ฟผ๋ฆฌ์ FROM ์ ์์ UDTF๋ฅผ ํธ์ถํ ๋ TABLE ํค์๋ ๋ค์์ ์ค๋ ๊ดํธ ์์ UDTF์ ์ด๋ฆ๊ณผ ์ธ์๋ฅผ ์ง์ ํฉ๋๋ค.
์ฆ, UDTF๋ฅผ ํธ์ถํ ๋ TABLE ํค์๋์ ๋ํด ๋ค์๊ณผ ๊ฐ์ ์์์ ์ฌ์ฉํฉ๋๋ค.
SELECT ...
FROM TABLE ( udtf_name (udtf_arguments) )
์ํ SQL UDTFยถ
๊ธฐ๋ณธ ์์ ยถ
์ด๋ ์ถ๋ ฅ์ ํ๋ ์ฝ๋ฉํ๋ ์ธ์์ ์ผ๋ก ๊ฐ๋จํ UDTF์ ์์
๋๋ค. ์ด๋ ๋ํ $$
๋ฅผ ๊ตฌ๋ถ ๊ธฐํธ๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
CREATE FUNCTION t()
RETURNS TABLE(msg VARCHAR)
AS
$$
SELECT 'Hello'
UNION
SELECT 'World'
$$;
SELECT msg
FROM TABLE(t())
ORDER BY msg;
+-------+
| MSG |
|-------|
| Hello |
| World |
+-------+
์ด ์๋ ์์ ์์ ์ ์ฌํ์ง๋ง ์์๋ฐ์ดํ๋ฅผ ๊ตฌ๋ถ ๊ธฐํธ๋ก ์ฌ์ฉํ๋ฉฐ, \
์ด์ค์ผ์ดํ ๋ฌธ์๋ฅผ ์ฌ์ฉํ์ฌ UDTF ๋ณธ๋ฌธ์์ ์์๋ฐ์ดํ๋ฅผ ์ด์ค์ผ์ดํํฉ๋๋ค.
CREATE FUNCTION t()
RETURNS TABLE(msg VARCHAR)
AS
'
SELECT \'Hello\'
UNION
SELECT \'World\'
';
SELECT msg
FROM TABLE(t())
ORDER BY msg;
+-------+
| MSG |
|-------|
| Hello |
| World |
+-------+
์ด๋ UDTF์ ๋ ๋ค๋ฅธ ๊ธฐ๋ณธ ์์ ๋๋ค. ํ ์ด๋ธ์ ์ฟผ๋ฆฌํ๊ณ ํด๋น ํ ์ด๋ธ์์ ๋ ๊ฐ์ ์ด์ ๋ฐํํฉ๋๋ค.
create or replace table orders (
product_id varchar,
quantity_sold numeric(11, 2)
);
insert into orders (product_id, quantity_sold) values
('compostable bags', 2000),
('re-usable cups', 1000);
create or replace function orders_for_product(PROD_ID varchar)
returns table (Product_ID varchar, Quantity_Sold numeric(11, 2))
as
$$
select product_ID, quantity_sold
from orders
where product_ID = PROD_ID
$$
;
select product_id, quantity_sold
from table(orders_for_product('compostable bags'))
order by product_id;
+------------------+---------------+
| PRODUCT_ID | QUANTITY_SOLD |
|------------------+---------------|
| compostable bags | 2000.00 |
+------------------+---------------+
์ด ๋์ผํ ๊ธฐ๋ฅ์ ๋ทฐ๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํํ ์๋ ์์ต๋๋ค.
์กฐ์ธ์ด ์๋ ์ยถ
์ง์ ๋ ์ฌ์ฉ์ ID์ ๋ํ ๊ตญ๊ฐ ์ ๋ณด(COUNTRY_CODE
๋ฐ COUNTRY_NAME
)๋ฅผ ๋ฐํํ๋ SQL UDTF๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๋ง๋ค๊ณ ์ฌ์ฉํ์ญ์์ค.
create or replace table countries (country_code char(2), country_name varchar);
insert into countries (country_code, country_name) values
('FR', 'FRANCE'),
('US', 'UNITED STATES'),
('ES', 'SPAIN');
create or replace table user_addresses (user_ID integer, country_code char(2));
insert into user_addresses (user_id, country_code) values
(100, 'ES'),
(123, 'FR'),
(123, 'US');
CREATE OR REPLACE FUNCTION get_countries_for_user ( id number )
RETURNS TABLE (country_code char, country_name varchar)
AS 'select distinct c.country_code, c.country_name
from user_addresses a, countries c
where a.user_id = id
and c.country_code = a.country_code';
select *
from table(get_countries_for_user(123)) cc
where cc.country_code in ('US','FR','CA')
order by country_code;
+--------------+---------------+
| COUNTRY_CODE | COUNTRY_NAME |
|--------------+---------------|
| FR | FRANCE |
| US | UNITED STATES |
+--------------+---------------+
์ง์ ๋ ์ฐ๋์ ๋ํด ์ ํธํ๋ ์์์ ๋ฐํํ๋ SQL UDTF๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๋ง๋์ญ์์ค.
create or replace table favorite_years as
select 2016 year
UNION ALL
select 2017
UNION ALL
select 2018
UNION ALL
select 2019;
create or replace table colors as
select 2017 year, 'red' color, true favorite
UNION ALL
select 2017 year, 'orange' color, true favorite
UNION ALL
select 2017 year, 'green' color, false favorite
UNION ALL
select 2018 year, 'blue' color, true favorite
UNION ALL
select 2018 year, 'violet' color, true favorite
UNION ALL
select 2018 year, 'brown' color, false favorite;
create or replace table fashion as
select 2017 year, 'red' fashion_color
UNION ALL
select 2018 year, 'black' fashion_color
UNION ALL
select 2019 year, 'orange' fashion_color;
create or replace function favorite_colors(the_year int)
returns table(color string) as
'select color from colors where year=the_year and favorite=true';
๋ค์๊ณผ ๊ฐ์ด ์ฟผ๋ฆฌ์์ UDTF๋ฅผ ์ฌ์ฉํ์ญ์์ค.
select color
from table(favorite_colors(2017))
order by color;
+--------+
| COLOR |
|--------|
| orange |
| red |
+--------+
๋ค๋ฅธ ํ ์ด๋ธ๊ณผ์ ์กฐ์ธ์์ UDTF๋ฅผ ์ฌ์ฉํ์ญ์์ค. ํ ์ด๋ธ์ ์กฐ์ธ ์ด์ด ํจ์์ ์ธ์๋ก ์ ๋ฌ๋ฉ๋๋ค.
select *
from favorite_years y join table(favorite_colors(y.year)) c
order by year, color;
+------+--------+
| YEAR | COLOR |
|------+--------|
| 2017 | orange |
| 2017 | red |
| 2018 | blue |
| 2018 | violet |
+------+--------+
์ถ๊ฐ ์กฐ๊ฑด์์ ๋ํด ๋ค์๊ณผ ๊ฐ์ด ON ๋์ WHERE ์ ์ ์ฌ์ฉํ์ญ์์ค.
select *
from fashion f join table(favorite_colors(f.year)) fav
where fav.color = f.fashion_color ;
+------+---------------+-------+
| YEAR | FASHION_COLOR | COLOR |
|------+---------------+-------|
| 2017 | red | red |
+------+---------------+-------+
์กฐ์ธ ์์์ ์์์ ํจ๊ป UDTF๋ฅผ ์ฌ์ฉํ์ญ์์ค. ์ถ๊ฐ ์กฐ์ธ ์กฐ๊ฑด์๋ ON ๋์ WHERE ์ ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
select fav.color as favorite_2017, f.*
from fashion f JOIN table(favorite_colors(2017)) fav
where fav.color = f.fashion_color
order by year;
+---------------+------+---------------+
| FAVORITE_2017 | YEAR | FASHION_COLOR |
|---------------+------+---------------|
| red | 2017 | red |
| orange | 2019 | orange |
+---------------+------+---------------+