ํ ์ด๋ธ ํ์ JavaScript UDF(UDTF)ยถ
JavaScript์์ ์ฌ์ฉ์ ์ ์ ํ ์ด๋ธ ํจ์ (UDTF)์ ์ฒ๋ฆฌ๊ธฐ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
์ฒ๋ฆฌ๊ธฐ ์ฝ๋๋ UDTF ํธ์ถ์์ ์์ ํ ํ์ ์ฒ๋ฆฌํ๊ณ ํ ์ด๋ธ ํ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค. ์์ ๋ ํ์ Snowflake์ ์ํด ์์์ ์ผ๋ก ๋ถํ ๋๊ฑฐ๋ ํจ์ ํธ์ถ ๊ตฌ๋ฌธ์์ ๋ช ์์ ์ผ๋ก ๋ถํ ๋ฉ๋๋ค. ๊ฐ๋ณ ํ์ ๋ฌผ๋ก ์ด๊ณ ๊ฐ๋ณ ํ์ด ๊ทธ๋ฃนํ๋ ํํฐ์ ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์์ฑํ๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
UDTF๊ฐ ์ ํจํ๋ ค๋ฉด JavaScript ์ฝ๋๊ฐ ๋ค์ ์๊ตฌ ์ฌํญ์ ์ถฉ์กฑํด์ผ ํฉ๋๋ค.
์ฝ๋๋ ๋จ์ผ ๋ฆฌํฐ๋ด JavaScript ์ค๋ธ์ ํธ๋ฅผ ์ ์ํด์ผ ํฉ๋๋ค.
์ ์๋ ์ค๋ธ์ ํธ๋
processRow()
๋ผ๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ํฌํจํด์ผ ํฉ๋๋ค. ์์ธํ ๋ด์ฉ์ ์ค๋ธ์ ํธ ์ฝ๋ฐฑ ํจ์ ์น์ ์ ์ฐธ์กฐํ์ญ์์ค.
์ค์
JavaScript ์ฝ๋๊ฐ ์ด๋ฌํ ์๊ตฌ ์ฌํญ์ ์ถฉ์กฑํ์ง ์๋ ๊ฒฝ์ฐ, UDTF๋ ๊ณ์ ๋ง๋ค์ด์ง์ง๋ง, ์ฟผ๋ฆฌ์์ ํธ์ถ ์ ์คํจํฉ๋๋ค.
์ฐธ๊ณ
ํ ์ด๋ธ ํ์ ํจ์(UDTF)์ ์ ๋ ฅ ์ธ์ 500๊ฐ, ์ถ๋ ฅ ์ด 500๊ฐ๋ก ์ ํ๋ฉ๋๋ค.
์ค๋ธ์ ํธ ์ฝ๋ฐฑ ํจ์ยถ
JavaScript ์ฝ๋๋ฅผ ํตํด Snowflake๋ ์ฟผ๋ฆฌ ์คํ ์ค์ ์ฝ๋ฐฑ ํจ์๋ฅผ ํธ์ถํ์ฌ UDTF์ ์ํธ ์์ฉํฉ๋๋ค. ๋ค์ ์ค์ผ๋ ํค์ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋ ์ฝ๋ฐฑ ํจ์์ ์์๋๋ ์๋ช ์ ๊ฐ๋ตํ๊ฒ ์ค๋ช ํฉ๋๋ค.
{
processRow: function (row, rowWriter, context) {/*...*/},
finalize: function (rowWriter, context) {/*...*/},
initialize: function (argumentInfo, context) {/*...*/},
}
processRow()
๋ง ํ์์
๋๋ค. ๋ค๋ฅธ ํจ์๋ ์ ํ ์ฌํญ์
๋๋ค.
processRow()
ยถ
์ด ์ฝ๋ฐฑ ํจ์๋ ์
๋ ฅ ๊ด๊ณ์ ๊ฐ ํ์ ๋ํด ํ ๋ฒ์ฉ ํธ์ถ๋ฉ๋๋ค. processRow()
์ ๋ํ ์ธ์๋ row
์ค๋ธ์ ํธ์ ์ ๋ฌ๋ฉ๋๋ค. UDTF๋ฅผ ๋ง๋๋ ๋ฐ ์ฌ์ฉ๋ CREATE FUNCTION ๋ฌธ์ ์ ์๋ ๊ฐ ์ธ์์ ๊ฒฝ์ฐ, ๋ชจ๋ ๋๋ฌธ์๋ก ๋ ๋์ผํ ์ด๋ฆ์ ๊ฐ์ง row
์ค๋ธ์ ํธ์ ์์ฑ์ด ์์ต๋๋ค. ์ด ์์ฑ์ ๊ฐ์ ํ์ฌ ํ์ ๋ํ ์ธ์ ๊ฐ์
๋๋ค. (๊ฐ์ JavaScript ๊ฐ์ผ๋ก ๋ณํ๋ฉ๋๋ค.)
rowWriter
์ธ์๋ ์ฌ์ฉ์ ์ ๊ณต ์ฝ๋์์ ์ถ๋ ฅ ํ์ ์์ฑํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. rowWriter
์ค๋ธ์ ํธ๋ ๋จ์ผ ํจ์์ธ writeRow()
๋ฅผ ์ ์ํฉ๋๋ค. writeRow()
ํจ์๋ ํ๋์ ์ธ์์ธ ํ ์ค๋ธ์ ํธ ๋ฅผ ์ฌ์ฉํ๋ฉฐ ์ด๋ JavaScript ์ค๋ธ์ ํธ๋ก ํ์๋๋ ์ถ๋ ฅ ํ
์ด๋ธ์ ๋จ์ผ ํ์
๋๋ค. CREATE FUNCTION ๋ช
๋ น์ RETURNS ์ ์ ์ ์๋ ๊ฐ ์ด์ ๊ฒฝ์ฐ, ํ ์ค๋ธ์ ํธ์ ํด๋น ์์ฑ์ ์ ์ํ ์ ์์ต๋๋ค. ํ ์ค๋ธ์ ํธ์ ํด๋น ์์ฑ ๊ฐ์ ์ถ๋ ฅ ๊ด๊ณ์์ ํด๋น ์ด์ ๊ฐ์ด ๋ฉ๋๋ค. ํ ์ค๋ธ์ ํธ์ ํด๋น ์์ฑ์ด ์๋ ์ถ๋ ฅ ์ด์ ๊ฒฐ๊ณผ ํ
์ด๋ธ์์ NULL ๊ฐ์ ๊ฐ์ต๋๋ค.
finalize()
ยถ
finalize()
์ฝ๋ฐฑ ํจ์๋ ๋ชจ๋ ํ์ด processRow()
์ ์ ๋ฌ๋ ํ ํ ๋ฒ ํธ์ถ๋ฉ๋๋ค. (๋ฐ์ดํฐ๊ฐ ํํฐ์
์ผ๋ก ๊ทธ๋ฃนํ๋๋ฉด ํด๋น ํํฐ์
์ ๋ชจ๋ ํ์ด processRow()
์ ์ ๋ฌ๋ ํ ๊ฐ ํํฐ์
์ ๋ํด finalize()
๊ฐ ํ ๋ฒ ํธ์ถ๋ฉ๋๋ค.)
์ด ์ฝ๋ฐฑ ํจ์๋ processRow()
์ ์ ๋ฌ๋ ๊ฒ๊ณผ ๋์ผํ ํ rowWriter
๋ฅผ ์ฌ์ฉํ์ฌ processRow()
์์ ์ง๊ณ๋์์ ์ ์๋ ๋ชจ๋ ์ํ๋ฅผ ์ถ๋ ฅํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ฐธ๊ณ
Snowflake๋ ์ฑ๊ณต์ ์ผ๋ก ์ฒ๋ฆฌํ๋๋ก ์๊ฐ ์ ํ์ด ์กฐ์ ๋ ๋ํ ํํฐ์
์ ์ง์ํ์ง๋ง, ํนํ ๋ํ ํํฐ์
์ผ๋ก ์ธํด ์ฒ๋ฆฌ ์๊ฐ์ด ์ด๊ณผ๋ ์ ์์ต๋๋ค(์: finalize
์ด ์๋ฃํ๋ ๋ฐ ๋๋ฌด ์ค๋ ๊ฑธ๋ฆฌ๋ ๊ฒฝ์ฐ). ํน์ ์ฌ์ฉ ์๋๋ฆฌ์ค์ ๋ง๊ฒ ์๊ฐ ์ด๊ณผ ์๊ณ๊ฐ์ ์กฐ์ ํด์ผ ํ๋ ๊ฒฝ์ฐ Snowflake ์ง์ ์ ๋ฌธ์ํ์ญ์์ค.
initialize()
ยถ
์ด ์ฝ๋ฐฑ ํจ์๋ processRow()
๋ฅผ ํธ์ถํ๊ธฐ ์ ์ ๊ฐ ํํฐ์
์ ๋ํด ํ ๋ฒ ํธ์ถ๋ฉ๋๋ค.
๊ฒฐ๊ณผ ๊ณ์ฐ ์ค์ ํ์ํ ์ํ๋ฅผ ์ค์ ํ๋ ค๋ฉด initialize()
๋ฅผ ์ฌ์ฉํ์ญ์์ค.
initialize()
ํจ์์ argumentInfo
๋งค๊ฐ ๋ณ์์๋ ์ฌ์ฉ์ ์ ์ ํจ์์ ๋ํ ์ธ์์ ๊ดํ ๋ฉํ๋ฐ์ดํฐ๊ฐ ํฌํจ๋์ด ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, UDF๊ฐ ๋ค์๊ณผ ๊ฐ์ด ์ ์๋ ๊ฒฝ์ฐ:
CREATE FUNCTION f(argument_1 INTEGER, argument_2 VARCHAR) ...
๊ทธ๋ฌ๋ฉด argumentInfo
๋ argument_1
๋ฐ argument_2
์ ๋ํ ์ ๋ณด๋ฅผ ํฌํจํฉ๋๋ค.
argumentInfo
์๋ ์ด๋ฌํ ๊ฐ ์ธ์์ ๋ํ ์์ฑ์ด ์์ต๋๋ค. ๊ฐ ์์ฑ์ ๋ค์ ๊ฐ์ ๊ฐ์ง ์ค๋ธ์ ํธ์
๋๋ค.
type
: ๋ฌธ์์ด์ ๋๋ค. ์ด ์ธ์์ ํ์์ ๋๋ค.isConst
: ๋ถ์ธ์ ๋๋ค. true์ด๋ฉด ์ด ์ธ์์ ๊ฐ์ ์์์ ๋๋ค(์ฆ, ๋ชจ๋ ํ์ ๋ํด ๋์ผํจ).constValue
:isConst
(์์ ์ ์๋จ)๊ฐ true์ด๋ฉด ์ด ํญ๋ชฉ์๋ ์ธ์์ ์์ ๊ฐ์ด ํฌํจ๋ฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ด ํ๋๋undefined
์ ๋๋ค.
initialize()
ํจ์๋ ์ถ๋ ฅ ํ์ ์์ฑํ ์ ์์ต๋๋ค.
์ฝ๋ฐฑ ํจ์์ ๋ํ ์ผ๋ฐ ์ฌ์ฉ๋ฒ ๋ ธํธยถ
์ธ ๊ฐ์ง ์ฝ๋ฐฑ ํจ์๋ ๋ชจ๋
context
์ค๋ธ์ ํธ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ ํฅํ ์ฌ์ฉ์ ์ํด ์์ฝ๋๋ฉฐ ํ์ฌ ๋น์ด ์์ต๋๋ค.์กฐ์ฌ
context
์ค๋ธ์ ํธ๋ฅผ ์์ ํ๋ฉด ์ ์๋์ง ์์ ๋์์ด ๋ฐ์ํ ์ ์์ต๋๋ค.ํ์์ ๋ฐ๋ผ UDTF์์ ์ฌ์ฉํ๊ธฐ ์ํด ์ค๋ธ์ ํธ์ ์ถ๊ฐ ํจ์ ๋ฐ ์์ฑ์ ์ ์ํ ์ ์์ต๋๋ค.
์ฝ๋ฐฑ ํจ์์ ๋ํ ์ธ์๋ ์์น ์ธ์์ด๋ฉฐ, ์ด๋ค ์ด๋ฆ์ผ๋ก๋ ์ง์ ํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด ํญ๋ชฉ์ ๋ชฉ์ ์ ์ํด ์์ ์ด๋ฆ์ด ๋๋จธ์ง ์ค๋ช ๋ฐ ์์ ์ฌ์ฉ๋ฉ๋๋ค.
ํํฐ์ ยถ
๋ง์ ์ํฉ์์ ํ์ ํํฐ์ ์ผ๋ก ๊ทธ๋ฃนํํ ์ ์์ต๋๋ค. ๋ถํ ์๋ ๋ค์๊ณผ ๊ฐ์ ๋ ๊ฐ์ง ์ฃผ์ ์ด์ ์ด ์์ต๋๋ค.
๊ณตํต ํน์ฑ์ ๋ฐ๋ผ ํ์ ๊ทธ๋ฃนํํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ๊ทธ๋ฃน ๋ด์ ๋ชจ๋ ํ์ ํจ๊ป ์ฒ๋ฆฌํ๊ณ ๊ฐ ๊ทธ๋ฃน์ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
์ด๋ฅผ ํตํด Snowflake๋ ์ํฌ๋ก๋๋ฅผ ๋ถํ ํ์ฌ ๋ณ๋ ฌ ์ฒ๋ฆฌ ๋ฐ ์ฑ๋ฅ์ ๊ฐ์ ํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ์ฃผ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ฃผ์๋น ํ๋์ ๊ทธ๋ฃน์ผ๋ก ๋ถํ ํ ์ ์์ต๋๋ค. ํ ๊ฐ๋ณ ํ์ฌ์ ๋ชจ๋ ์ฃผ๊ฐ๋ ํจ๊ป ์ฒ๋ฆฌ๋ ์ ์์ผ๋ฉฐ, ์๋ก ๋ค๋ฅธ ํ์ฌ์ ๊ทธ๋ฃน์ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
๋ค์ ๋ฌธ์ ๊ฐ๋ณ ํํฐ์
์์ js_udtf()
๋ผ๋ UDTF๋ฅผ ํธ์ถํฉ๋๋ค. ๊ฐ ํํฐ์
์๋ PARTITION BY
์์ด ๋์ผ ๊ฐ(์: ๋์ผํ ์ฃผ์ ๊ธฐํธ)์ผ๋ก ํ๊ฐ๋๋ ๋ชจ๋ ํ์ด ํฌํจ๋ฉ๋๋ค.
SELECT * FROM tab1, TABLE(js_udtf(tab1.c1, tab1.c2) OVER (PARTITION BY <expression>)) ...;
UDTF์ ํจ๊ป ์ฌ์ฉํ ํํฐ์ ์์ ์ง์ ํ๋ฉด Snowflake๋ ๋ค์์ ํธ์ถํฉ๋๋ค.
initialize()
: ๊ฐ ํํฐ์ ์ ๋ํด ํ ๋ฒ์ฉ ํธ์ถํฉ๋๋ค.processRow()
: ํด๋น ํํฐ์ ์ ๊ฐ ๊ฐ๋ณ ํ์ ๋ํด ํ ๋ฒ์ฉ ํธ์ถํฉ๋๋ค.finalize()
: ๊ฐ ํํฐ์ ์ ๋ํด ํ ๋ฒ์ฉ ํธ์ถํฉ๋๋ค(ํด๋น ํํฐ์ ์ ๋ง์ง๋ง ํ์ ์ฒ๋ฆฌํ ํ).
๊ฐ ํํฐ์ ์ ํ์ ์ง์ ๋ ์์๋ก ์ฒ๋ฆฌํ ์๋ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์๊ฐ ๊ฒฝ๊ณผ์ ๋ฐ๋ฅธ ์ฃผ๊ฐ์ ์ด๋ ํ๊ท ์ ๊ณ์ฐํ๋ ค๋ฉด ํ์์คํฌํ๋ฅผ ๊ธฐ์ค์ผ๋ก ์ฃผ๊ฐ๋ฅผ ์ ๋ ฌํ์ญ์์ค(๋ํ ์ฃผ์ ๋๋ ํ์ฌ๋ณ๋ก ๋ถํ ). ๋ค์ ์์์๋ ์ด ์์ ์ ์ํํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
SELECT * FROM tab1, TABLE(js_udtf(tab1.c1, tab1.c2) OVER (PARTITION BY <expression> ORDER BY <expression>)) ...;
ORDER BY
์ ์ ์ง์ ํ๋ ๊ฒฝ์ฐ, ORDER BY
์์์ ์ ์ํ ์์๋๋ก ํ์ด ์ฒ๋ฆฌ๋ฉ๋๋ค. ํนํ, ํ์ ORDER BY
์์ ์ํด ์ ์๋ ์์๋๋ก processRow()
์ ์ ๋ฌ๋ฉ๋๋ค.
๋๋ถ๋ถ์ ๊ฒฝ์ฐ, ๋ฐ์ดํฐ๋ฅผ ๋ถํ ํ๋ฉด ๋ณ๋ ฌ ์ฒ๋ฆฌ ๊ธฐํ๊ฐ ๊ฑฐ์ ์๋์ผ๋ก ํฅ์๋์ด ์ฑ๋ฅ์ด ํฅ์๋ฉ๋๋ค. Snowflake๋ ์ผ๋ฐ์ ์ผ๋ก ์ฌ๋ฌ UDTF ์ธ์คํด์ค ๋ฅผ ๋ณ๋ ฌ๋ก ์คํํฉ๋๋ค. (์ด ๋ ผ์์์ JavaScript UDTF์ ์ธ์คํด์ค๋ Snowflake์์ ํจ์๋ฅผ ๋ํ๋ด๋ ๋ฐ ์ฌ์ฉ๋๋ JavaScript ์ค๋ธ์ ํธ์ ํ ์ธ์คํด์ค๋ก ์ ์๋ฉ๋๋ค.) ํ์ ๊ฐ ํํฐ์ ์ UDTF์ ๋จ์ผ ์ธ์คํด์ค๋ก ์ ๋ฌ๋ฉ๋๋ค.
๊ทธ๋ฌ๋ ํํฐ์
๊ณผ UDTF ์ธ์คํด์ค ์ฌ์ด์ ๋ฐ๋์ ์ผ๋์ผ ๊ด๊ณ๊ฐ ์๋ ๊ฒ์ ์๋๋๋ค. ๊ฐ ํํฐ์
์ ํ๋์ UDTF ์ธ์คํด์ค์์๋ง ์ฒ๋ฆฌ๋์ง๋ง, ๊ทธ ๋ฐ๋์ ๊ฒฝ์ฐ์๋ ๋ฐ๋์ ๊ทธ๋ฐ ๊ฒ์ ์๋๋๋ค. ์ฆ, ๋จ์ผ UDTF ์ธ์คํด์ค๋ ์ฌ๋ฌ ํํฐ์
์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ initialize()
๋ฐ finalize()
๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ํํฐ์
์ ๊ตฌ์ฒด์ ์ผ๋ก ์ค์ ํ๊ณ ์ญ์ ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด๋ ์๋ฅผ ๋ค์ด, ํ ํํฐ์
์ ์ฒ๋ฆฌ์์ ๋ค๋ฅธ ํํฐ์
์ ์ฒ๋ฆฌ๋ก ๋์ ๊ฐ์ โ์ ๋ฌโํ๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํจ์
๋๋ค.
๊ฒฐ๊ณผ ์ดยถ
์์ ๋ถํ ์์ ์ฒ๋ผ ํ ์ด๋ธ์ด ํ ์ด๋ธ ํจ์์ ์กฐ์ธ๋๋ฉด ๊ฒฐ๊ณผ ์งํฉ์๋ ์ ํํ ๋ด์ฉ์ ๋ฐ๋ผ ๋ค์์ด ํฌํจ๋ ์ ์์ต๋๋ค.
CREATE FUNCTION ๋ช ๋ น์ RETURNS ์ ์ ์ ์๋ ์ด์ ๋๋ค.
ํ ์ด๋ธ์ ์ด์ ๋ฐ์ดํฐ๋ฅผ ๋ถํ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ ์ด๊ณผ UDTF์ ์ ๋ ฅ ๋งค๊ฐ ๋ณ์๋ก ์ฌ์ฉ๋๋์ง ์ฌ๋ถ์ ๊ด๊ณ์์ด ๋ค๋ฅธ ์ด์ ๋ชจ๋ ํฌํจํฉ๋๋ค.
processRow
์ฝ๋ฐฑ์์ ์์ฑ๋๋ ํ๊ณผ finalize
์์ ์์ฑ๋๋ ํ์ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ค๋ฆ
๋๋ค.
processRow
์์ ํ์ด ์์ฑ๋๋ฉด Snowflake๋ ์ด๋ฅผ ์ ๋ ฅ ํ, ์ฆrow
์ธ์๋ก์ ํจ์์ ์ ๋ฌ๋ ํญ๋ชฉ์ ๋ํด ์๊ด ๊ด๊ณ๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. ์ฃผ์ด์งprocessRow
ํธ์ถ์ด ๋ ๊ฐ ์ด์์ ํ์ ์์ฑํ๋ ๊ฒฝ์ฐ ์ ๋ ฅ ํน์ฑ์ ๊ฐ ์ถ๋ ฅ ํ๊ณผ ์๊ด๊ด๊ณ๊ฐ ์๋ค๋ ์ ์ ์ ์ํ์ญ์์ค.processRow
์์ ์์ฑ๋ ํ์ ๊ฒฝ์ฐ ๋ชจ๋ ์ ๋ ฅ ์ด์ ์ถ๋ ฅ ๊ด๊ณ์ ์กฐ์ธํ ์ ์์ต๋๋ค.
finalize
์ฝ๋ฐฑ์์ Snowflake๋ ์๊ด ๊ด๊ณ๋ฅผ ์ง์ ํ โํ์ฌ ํโ์ด ์๊ธฐ ๋๋ฌธ์ ๋จ์ผ ํ์ ๋ํด ์๊ด ๊ด๊ณ๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค.
finalize
์ฝ๋ฐฑ์์ ์์ฑ๋ ํ์ ๊ฒฝ์ฐ, PARTITION BY ์ ์ ์ฌ์ฉ๋ ์ด๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค(์ด๋ฌํ ํญ๋ชฉ์ ํ์ฌ ํํฐ์ ์ ๋ชจ๋ ํ์ ๋ํด ๋์ผํ๋ฏ๋ก). ๊ธฐํ ๋ชจ๋ ์์ฑ์ NULL์ ๋๋ค. PARTITION BY ์ ์ด ์ง์ ๋์ง ์์ ๊ฒฝ์ฐ ๋ชจ๋ ํด๋น ํน์ฑ์ NULL์ ๋๋ค.
์ฟผ๋ฆฌ์์ JavaScript UDTF ํธ์ถํ๊ธฐยถ
์ฟผ๋ฆฌ์ FROM ์ ์์ UDTF๋ฅผ ํธ์ถํ ๋ TABLE ํค์๋ ๋ค์์ ์ค๋ ๊ดํธ ์์ UDTF์ ์ด๋ฆ๊ณผ ์ธ์๋ฅผ ์ง์ ํฉ๋๋ค.
์ฆ, UDTF๋ฅผ ํธ์ถํ ๋ TABLE ํค์๋์ ๋ํด ๋ค์๊ณผ ๊ฐ์ ์์์ ์ฌ์ฉํฉ๋๋ค.
SELECT ...
FROM TABLE ( udtf_name (udtf_arguments) )
์ฐธ๊ณ
UDF ๋ฐ UDTF ํธ์ถ์ ๋ํ ์์ธํ ๋ด์ฉ์ UDF ์คํํ๊ธฐ ์น์ ์ ์ฐธ์กฐํ์ญ์์ค.
๋ถํ ์์ยถ
์ด ๊ฐ๋จํ ์๋ UDTF๋ฅผ ํธ์ถํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. ์ด ์๋ ๋ฆฌํฐ๋ด ๊ฐ์ ์ ๋ฌํฉ๋๋ค. UDTF๋ ์ ๋ฌ๋ ์์์ ์ญ์์ผ๋ก ๋งค๊ฐ ๋ณ์๋ฅผ ๋ฐํํ ๋ฟ์ ๋๋ค. ์ด ์์์๋ ๋ถํ ์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
SELECT * FROM TABLE(js_udtf(10.0::FLOAT, 20.0::FLOAT));
+----+----+
| Y | X |
|----+----|
| 20 | 10 |
+----+----+
์ด ์๋ UDTF๋ฅผ ํธ์ถํ๊ณ ๋ค๋ฅธ ํ
์ด๋ธ์ ๊ฐ์ ์ ๋ฌํฉ๋๋ค. ์ด ์์์ js_udtf
๋ผ๋ UDTF๋ tab1
์ด๋ผ๋ ํ
์ด๋ธ์ ๊ฐ ํ์ ๋ํด ํ ๋ฒ์ฉ ํธ์ถ๋ฉ๋๋ค. ํจ์๊ฐ ํธ์ถ๋ ๋๋ง๋ค ํ์ฌ ํ์ c1
๋ฐ c2
์ด์์ ๊ฐ์ด ์ ๋ฌ๋ฉ๋๋ค. ์์ ๊ฐ์ด UDTF๋ PARTITION BY
์ ์์ด ํธ์ถ๋ฉ๋๋ค.
SELECT * FROM tab1, TABLE(js_udtf(tab1.c1, tab1.c2)) ;
๋ถํ ์ด ์ฌ์ฉ๋์ง ์๋ ๊ฒฝ์ฐ, Snowflake ์คํ ์์ง์ ํจ์๋ฅผ ์ฒ๋ฆฌํ๋ ์จ์ดํ์ฐ์ค์ ํฌ๊ธฐ ๋ฐ ์ ๋ ฅ ๊ด๊ณ์ ์นด๋๋๋ฆฌํฐ์ ๊ฐ์ ์ฌ๋ฌ ์์ธ์ ๋ฐ๋ผ ์ ๋ ฅ ์์ฒด๋ฅผ ๋ถํ ํฉ๋๋ค. ์ด ๋ชจ๋์์ ์คํํ ๋ ์ฌ์ฉ์ ์ฝ๋๋ ํํฐ์ ์ ๋ํด ๊ฐ์ ํ ์ ์์ต๋๋ค. ์ด๋ ํจ์๊ฐ ์ถ๋ ฅ์ ์์ฑํ๊ธฐ ์ํด ๊ฐ๋ณ์ ์ผ๋ก ํ๋ง ๋ณผ ํ์๊ฐ ์๊ณ ํ ๊ฐ์ ์ง๊ณ๋ ์ํ๊ฐ ์๋ ๊ฒฝ์ฐ์ ๊ฐ์ฅ ์ ์ฉํฉ๋๋ค.
๋ช ์์ ๋ถํ ยถ
JavaScript UDTF๋ ํํฐ์ ์ ์ฌ์ฉํ์ฌ ํธ์ถํ ์๋ ์์ต๋๋ค. ์:
SELECT * FROM tab1, TABLE(js_udtf(tab1.c1, tab1.c2) OVER (PARTITION BY tab1.c3 ORDER BY tab1.c1));
๋น OVER
์ ์ ์ฌ์ฉํ ๋ช
์์ ๋ถํ ยถ
SELECT * FROM tab1, TABLE(js_udtf(tab1.c1, tab1.c2) OVER ());
๋น OVER
์ ์ ๋ชจ๋ ํ์ด ๋์ผ ํํฐ์
์ ์ํจ์ ์๋ฏธํฉ๋๋ค(์ฆ, ์ ์ฒด ์
๋ ฅ ๊ด๊ณ๊ฐ ํ๋์ ํํฐ์
์).
์ฐธ๊ณ
๋น OVER
์ ์ ์ฌ์ฉํ์ฌ JavaScript UDTF๋ฅผ ํธ์ถํ ๋๋ ์ฃผ์ํด์ผ ํฉ๋๋ค. ์ด๋ Snowflake๊ฐ ํจ์์ ์ธ์คํด์ค ํ๋๋ฅผ ์์ฑํ๋๋ก ์ ํํ๋ฏ๋ก Snowflake๊ฐ ๊ณ์ฐ์ ๋ณ๋ ฌ ์ฒ๋ฆฌํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค.
์ํ JavaScript UDTFยถ
์ด ์น์ ์๋ ์ฌ๋ฌ ์ํ JavaScript UDTF๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
๊ธฐ๋ณธ์ ์ธ Hello World
์ยถ
๋ค์ JavaScript UDTF๋ ๋งค๊ฐ ๋ณ์๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉฐ, ๋์ผํ ๊ฐ์ ํญ์ ๋ฐํํฉ๋๋ค. ์ฃผ๋ก ์ค๋ช ๋ชฉ์ ์ผ๋ก ์ ๊ณต๋ฉ๋๋ค.
CREATE OR REPLACE FUNCTION HelloWorld0()
RETURNS TABLE (OUTPUT_COL VARCHAR)
LANGUAGE JAVASCRIPT
AS '{
processRow: function f(row, rowWriter, context){
rowWriter.writeRow({OUTPUT_COL: "Hello"});
rowWriter.writeRow({OUTPUT_COL: "World"});
}
}';
SELECT output_col FROM TABLE(HelloWorld0());
์ถ๋ ฅ:
+------------+
| OUTPUT_COL |
+============+
| Hello |
+------------+
| World |
+------------+
๋ค์ JavaScript UDTF๋ ์ค๋ช ์ ์ํ ๊ฒ์ด์ง๋ง, ์ ๋ ฅ ๋งค๊ฐ ๋ณ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. JavaScript๋ ๋/์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง๋ง, SQL์ ์๋ณ์๋ฅผ ๋๋ฌธ์๋ก ๊ฐ์ ํ๋ฏ๋ก JavaScript ์ฝ๋๊ฐ SQL ๋งค๊ฐ ๋ณ์ ์ด๋ฆ์ ์ฐธ์กฐํ ๋ JavaScript ์ฝ๋๋ ๋๋ฌธ์๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
๋ํ, ํจ์ ๋งค๊ฐ ๋ณ์๋ get_params()
ํจ์์์ row
๋ผ๋ ๋งค๊ฐ ๋ณ์๋ฅผ ํตํด ์ก์ธ์ค๋ฉ๋๋ค.
CREATE OR REPLACE FUNCTION HelloHuman(First_Name VARCHAR, Last_Name VARCHAR)
RETURNS TABLE (V VARCHAR)
LANGUAGE JAVASCRIPT
AS '{
processRow: function get_params(row, rowWriter, context){
rowWriter.writeRow({V: "Hello"});
rowWriter.writeRow({V: row.FIRST_NAME}); // Note the capitalization and the use of "row."!
rowWriter.writeRow({V: row.LAST_NAME}); // Note the capitalization and the use of "row."!
}
}';
SELECT V AS Greeting FROM TABLE(HelloHuman('James', 'Kirk'));
์ถ๋ ฅ:
+------------+
| GREETING |
+============+
| Hello |
+------------+
| James |
+------------+
| Kirk |
+------------+
์ฝ๋ฐฑ ํจ์๋ฅผ ๋ณด์ฌ์ฃผ๋ ๊ธฐ๋ณธ ์ยถ
๋ค์ JavaScript UDTF๋ ๋ชจ๋ API ์ฝ๋ฐฑ ํจ์์ ๋ค์ํ ์ถ๋ ฅ ์ด์ ๋ณด์ฌ์ค๋๋ค. ๋จ์ํ ๋ชจ๋ ํ์ ์๋ ๊ทธ๋๋ก ๋ฐํํ๋ฉฐ, ๊ฐ ํํฐ์
์ ํ์๋ ๋ฌธ์ ์๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ํ, THIS
์ฐธ์กฐ๋ฅผ ์ฌ์ฉํ์ฌ ํํฐ์
์์ ์ํ๋ฅผ ๊ณต์ ํ๋ ๋ฐฉ๋ฒ๋ ๋ณด์ฌ์ค๋๋ค. ์ด ์์์๋ initialize()
์ฝ๋ฐฑ์ ์ฌ์ฉํ์ฌ ์นด์ดํฐ๋ฅผ 0์ผ๋ก ์ด๊ธฐํํฉ๋๋ค. ์ด๋ ์ฃผ์ด์ง ํจ์ ์ธ์คํด์ค๊ฐ ์ฌ๋ฌ ํํฐ์
์ ์ฒ๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์๊ธฐ ๋๋ฌธ์ ํ์ํฉ๋๋ค.
-- set up for the sample
CREATE TABLE parts (p FLOAT, s STRING);
INSERT INTO parts VALUES (1, 'michael'), (1, 'kelly'), (1, 'brian');
INSERT INTO parts VALUES (2, 'clara'), (2, 'maggie'), (2, 'reagan');
-- creation of the UDTF
CREATE OR REPLACE FUNCTION "CHAR_SUM"(INS STRING)
RETURNS TABLE (NUM FLOAT)
LANGUAGE JAVASCRIPT
AS '{
processRow: function (row, rowWriter, context) {
this.ccount = this.ccount + 1;
this.csum = this.csum + row.INS.length;
rowWriter.writeRow({NUM: row.INS.length});
},
finalize: function (rowWriter, context) {
rowWriter.writeRow({NUM: this.csum});
},
initialize: function(argumentInfo, context) {
this.ccount = 0;
this.csum = 0;
}}';
๋ค์ ์ฟผ๋ฆฌ๋ ๋ถํ ์์ด parts
ํ
์ด๋ธ์์ CHAR_SUM
UDTF๋ฅผ ํธ์ถํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
SELECT * FROM parts, TABLE(char_sum(s));
์ถ๋ ฅ:
+--------+---------+-----+
| P | S | NUM |
+--------+---------+-----+
| 1 | michael | 7 |
| 1 | kelly | 5 |
| 1 | brian | 5 |
| 2 | clara | 5 |
| 2 | maggie | 6 |
| 2 | reagan | 6 |
| [NULL] | [NULL] | 34 |
+--------+---------+-----+
ํํฐ์
์ ์ง์ ํ์ง ์์ผ๋ฉด Snowflake๊ฐ ์๋์ผ๋ก ํํฐ์
์ ์ ์ํฉ๋๋ค. ์ด ์์์๋ ํ ์๊ฐ ์ ๊ธฐ ๋๋ฌธ์ ํํฐ์
์ด ํ๋๋ง ์์ฑ๋ฉ๋๋ค(์ฆ, finalize()
ํธ์ถ์ด ํ๋๋ง ์คํ๋จ). ๋ง์ง๋ง ํ์ ์
๋ ฅ ์ด์๋ NULL ๊ฐ์ด ์์ต๋๋ค.
๋์ผํ ์ฟผ๋ฆฌ์ด์ง๋ง, ๋ค์๊ณผ ๊ฐ์ด ๋ช ์์ ๋ถํ ์ ์ฌ์ฉํฉ๋๋ค.
SELECT * FROM parts, TABLE(char_sum(s) OVER (PARTITION BY p));
์ถ๋ ฅ:
+--------+---------+-----+
| P | S | NUM |
+--------+---------+-----+
| 1 | michael | 7 |
| 1 | kelly | 5 |
| 1 | brian | 5 |
| 1 | [NULL] | 17 |
| 2 | clara | 5 |
| 2 | maggie | 6 |
| 2 | reagan | 6 |
| 2 | [NULL] | 17 |
+--------+---------+-----+
์ด ์์์๋ p
์ด์ ๋ํด ๋ถํ ํ์ฌ ๋ ๊ฐ์ ํํฐ์
์ ์์ฑํฉ๋๋ค. ๊ฐ ํํฐ์
์ ๋ํด finalize()
์ฝ๋ฐฑ์์ ๋จ์ผ ํ์ด ๋ฐํ๋์ด ์ด ๋ ๊ฐ์ ํ์ ์์ฑํ๋ฉฐ ์ด๋ s
์ด์ NULL ๊ฐ์ผ๋ก ๊ตฌ๋ถ๋ฉ๋๋ค. p
๋ PARTITION BY ์ด์ด๋ฏ๋ก finalize()
์์ ์์ฑ๋ ํ์ ํ์ฌ ํํฐ์
์ ์ ์ํ๋ p
๊ฐ์ ๊ฐ์ต๋๋ค.
ํ ์ด๋ธ ๊ฐ ๋ฐ ๊ธฐํ UDTF๋ฅผ ์ ๋ ฅ์ผ๋ก ์ฌ์ฉํ๋ ํ์ฅ๋ ์ยถ
์ด ๊ธฐ๋ณธ UDTF๋ IP ์ฃผ์์ โ๋ฒ์โ๋ฅผ ์ ์ฒด IP ์ฃผ์ ๋ชฉ๋ก์ผ๋ก ๋ณํํฉ๋๋ค. ์
๋ ฅ์ IP ์ฃผ์์ ์ฒ์ 3๊ฐ ์ธ๊ทธ๋จผํธ(์: '192.168.1'
), ๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง ์ธ๊ทธ๋จผํธ๋ฅผ ์์ฑํ๋ ๋ฐ ์ฌ์ฉ๋ ๋ฒ์์ ์์ ๋ฐ ๋(์: 42
๋ฐ 45
)์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
CREATE OR REPLACE FUNCTION range_to_values(PREFIX VARCHAR, RANGE_START FLOAT, RANGE_END FLOAT)
RETURNS TABLE (IP_ADDRESS VARCHAR)
LANGUAGE JAVASCRIPT
AS $$
{
processRow: function f(row, rowWriter, context) {
var suffix = row.RANGE_START;
while (suffix <= row.RANGE_END) {
rowWriter.writeRow( {IP_ADDRESS: row.PREFIX + "." + suffix} );
suffix = suffix + 1;
}
}
}
$$;
SELECT * FROM TABLE(range_to_values('192.168.1', 42::FLOAT, 45::FLOAT));
์ถ๋ ฅ:
+--------------+
| IP_ADDRESS |
+==============+
| 192.168.1.42 |
+--------------+
| 192.168.1.43 |
+--------------+
| 192.168.1.44 |
+--------------+
| 192.168.1.45 |
+--------------+
์ด์ ์๋ฅผ ๋ฐํ์ผ๋ก ๋ ์ด์์ ๋ฒ์์ ๋ํ ๊ฐ๋ณ IP ์ฃผ์๋ฅผ ๊ณ์ฐํ ์ ์์ต๋๋ค. ๋ค์ ๋ฌธ์ ๊ฐ๋ณ IP ์ฃผ์๋ก ํ์ฅํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ ๋ฒ์ ํ
์ด๋ธ์ ๋ง๋ญ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ฟผ๋ฆฌ๋ ํ
์ด๋ธ์ ํ์ range_to_values()
UDTF์ ์
๋ ฅํ์ฌ ๊ฐ๋ณ IP ์ฃผ์๋ฅผ ๋ฐํํฉ๋๋ค.
CREATE TABLE ip_address_ranges(prefix VARCHAR, range_start INTEGER, range_end INTEGER);
INSERT INTO ip_address_ranges (prefix, range_start, range_end) VALUES
('192.168.1', 42, 44),
('192.168.2', 10, 12),
('192.168.2', 40, 40)
;
SELECT rtv.ip_address
FROM ip_address_ranges AS r, TABLE(range_to_values(r.prefix, r.range_start::FLOAT, r.range_end::FLOAT)) AS rtv;
์ถ๋ ฅ:
+--------------+
| IP_ADDRESS |
+==============+
| 192.168.1.42 |
+--------------+
| 192.168.1.43 |
+--------------+
| 192.168.1.44 |
+--------------+
| 192.168.2.10 |
+--------------+
| 192.168.2.11 |
+--------------+
| 192.168.2.12 |
+--------------+
| 192.168.2.40 |
+--------------+
์ฃผ์
์ด ์์์ FROM ์ ์ ์ฌ์ฉ๋ ๊ตฌ๋ฌธ์ ๋ด๋ถ ์กฐ์ธ์ ๊ตฌ๋ฌธ(์ฆ, FROM t1, t2
)๊ณผ ๋์ผํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ํ๋ ์์
์ ์ค์ ๋ด๋ถ ์กฐ์ธ์ด ์๋๋๋ค. ์ค์ ๋์์ range_to_values()
ํจ์๊ฐ ip_address changes
ํ
์ด๋ธ์ ์๋ ๊ฐ ํ์ ๊ฐ์ผ๋ก ํธ์ถ๋๋ค๋ ๊ฒ์
๋๋ค. ์ฆ, ๋ค์๊ณผ ๊ฐ์ด ์ฐ๋ ๊ฒ๊ณผ ๋์ผํฉ๋๋ค.
for input_row in ip_address_ranges: output_row = range_to_values(input_row.prefix, input_row.range_start, input_row.range_end)
UDTF์ ๊ฐ์ ์ ๋ฌํ๋ค๋ ๊ฐ๋
์ ์ฌ๋ฌ UDTF๋ก ํ์ฅ๋ ์ ์์ต๋๋ค. ๋ค์ ์๋ IPV4 ์ฃผ์๋ฅผ IPV6 ์ฃผ์๋ก โ๋ณํโํ๋ fake_ipv4_to_ipv6()
์ด๋ผ๋ UDTF๋ฅผ ๋ง๋ญ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ฟผ๋ฆฌ๋ ๋ค๋ฅธ UDTF๋ฅผ ํฌํจํ๋ ๋ณด๋ค ๋ณต์กํ ๋ฌธ์ ์ผ๋ถ๋ก์ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
-- Example UDTF that "converts" an IPV4 address to a range of IPV6 addresses.
-- (for illustration purposes only and is not intended for actual use)
CREATE OR REPLACE FUNCTION fake_ipv4_to_ipv6(ipv4 VARCHAR)
RETURNS TABLE (IPV6 VARCHAR)
LANGUAGE JAVASCRIPT
AS $$
{
processRow: function f(row, rowWriter, context) {
rowWriter.writeRow( {IPV6: row.IPV4 + "." + "000.000.000.000"} );
rowWriter.writeRow( {IPV6: row.IPV4 + "." + "..."} );
rowWriter.writeRow( {IPV6: row.IPV4 + "." + "FFF.FFF.FFF.FFF"} );
}
}
$$;
SELECT ipv6 FROM TABLE(fake_ipv4_to_ipv6('192.168.3.100'));
์ถ๋ ฅ:
+-------------------------------+
| IPV6 |
+===============================+
| 192.168.3.100.000.000.000.000 |
+-------------------------------+
| 192.168.3.100.... |
+-------------------------------+
| 192.168.3.100.FFF.FFF.FFF.FFF |
+-------------------------------+
๋ค์ ์ฟผ๋ฆฌ๋ ip_address changes
ํ
์ด๋ธ์ ์
๋ ฅ๊ณผ ํจ๊ป, ์ด์ ์ ์์ฑ๋ fake_ipv4_to_ipv6
๋ฐ range_to_values()
UDTF๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ฆ, IP ์ฃผ์ ๋ฒ์ ์ธํธ๋ก ์์ํ์ฌ ์ด๋ฅผ ๊ฐ๋ณ IPV4 ์ฃผ์๋ก ๋ณํํ ๋ค์, ๊ฐ IPV4 ์ฃผ์๋ฅผ ๊ฐ์ ธ์ IPV6 ์ฃผ์ ๋ฒ์๋ก โ๋ณํโํฉ๋๋ค.
SELECT rtv6.ipv6
FROM ip_address_ranges AS r,
TABLE(range_to_values(r.prefix, r.range_start::FLOAT, r.range_end::FLOAT)) AS rtv,
TABLE(fake_ipv4_to_ipv6(rtv.ip_address)) AS rtv6
WHERE r.prefix = '192.168.2' -- limits the output for this example
;
์ถ๋ ฅ:
+------------------------------+
| IPV6 |
+==============================+
| 192.168.2.10.000.000.000.000 |
+------------------------------+
| 192.168.2.10.... |
+------------------------------+
| 192.168.2.10.FFF.FFF.FFF.FFF |
+------------------------------+
| 192.168.2.11.000.000.000.000 |
+------------------------------+
| 192.168.2.11.... |
+------------------------------+
| 192.168.2.11.FFF.FFF.FFF.FFF |
+------------------------------+
| 192.168.2.12.000.000.000.000 |
+------------------------------+
| 192.168.2.12.... |
+------------------------------+
| 192.168.2.12.FFF.FFF.FFF.FFF |
+------------------------------+
| 192.168.2.40.000.000.000.000 |
+------------------------------+
| 192.168.2.40.... |
+------------------------------+
| 192.168.2.40.FFF.FFF.FFF.FFF |
+------------------------------+
์ด ์์์๋ ์กฐ์ธ ๊ตฌ๋ฌธ์ ๋ ๋ฒ ์ฌ์ฉํ์ง๋ง, ๋ ์์ ๋ชจ๋ ์ค์ ์กฐ์ธ์ด ์๋์์ต๋๋ค. ๋ ๋ค ํ ์ด๋ธ์ ์ถ๋ ฅ์ด๋ ๋ค๋ฅธ UDTF๋ฅผ ์ ๋ ฅ์ผ๋ก ์ฌ์ฉํ๋ UDTF์ ๋ํ ํธ์ถ์ด์์ต๋๋ค.
์ค์ ๋ด๋ถ ์กฐ์ธ์ ์์๋ฅผ ๊ตฌ๋ถํ์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๋ค์ ๋ฌธ์ ๋์ผํฉ๋๋ค.
table1 INNER JOIN table2 ON ...
table2 INNER JOIN table1 ON ...
UDTF์ ๊ฐ์ ์ ๋ ฅํ๋ ๊ฒ์ ์ค์ ์กฐ์ธ์ด ์๋๋ฉฐ ์์ ์ ์์๋ฅผ ๊ตฌ๋ถํ์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ค์ ์ฟผ๋ฆฌ๋ FROM ์ ์์ UDTF์ ์์๋ฅผ ๋ฐ๋๋ก ํ๋ค๋ ์ ์ ์ ์ธํ๊ณ ๋ ์ด์ ์์ ๋์ผํฉ๋๋ค.
SELECT rtv6.ipv6
FROM ip_address_ranges AS r,
TABLE(fake_ipv4_to_ipv6(rtv.ip_address)) AS rtv6,
TABLE(range_to_values(r.prefix, r.range_start::FLOAT, r.range_end::FLOAT)) AS rtv
WHERE r.prefix = '192.168.2' -- limits the output for this example
;
์ฟผ๋ฆฌ๋ ๋ค์ ์ค๋ฅ ๋ฉ์์ง์ ํจ๊ป ์คํจํฉ๋๋ค.
SQL compilation error: error line 3 at position 35 invalid identifier 'RTV.IP_ADDRESS'
rtv.ip_address
์๋ณ์๋ ์ ํจํ์ง ์์ต๋๋ค. ์ฌ์ฉ๋๊ธฐ ์ ์ ์ ์๋์ง ์์๊ธฐ ๋๋ฌธ์
๋๋ค. ์ค์ ์กฐ์ธ์์๋ ์ด๋ฐ ์ผ์ด ์ผ์ด๋์ง ์์ง๋ง, ์กฐ์ธ ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ UDTF๋ฅผ ์ฒ๋ฆฌํ ๋ ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ค์์ผ๋ก, UDTF์ ๋ํ ์ ๋ ฅ์ ์ค์ ์กฐ์ธ๊ณผ ํผํฉํ๋ ๋ฌธ์ ์ฌ์ฉํด ๋ณด์ญ์์ค. ๊ทธ๋ฌ๋ UDTF์ ์ ๋ ฅํ๋ ๊ฒ๊ณผ ๋ด๋ถ ์กฐ์ธ์ ์ํํ๋ ๊ฒ์ ๋ ๋ค ๋์ผํ ๊ตฌ๋ฌธ์ ์ฌ์ฉํ๋ฏ๋ก ํผ๋๋ ์ ์์์ ๊ธฐ์ตํ์ญ์์ค.
-- First, create a small table of IP address owners.
-- This table uses only IPv4 addresses for simplicity.
DROP TABLE ip_address_owners;
CREATE TABLE ip_address_owners (ip_address VARCHAR, owner_name VARCHAR);
INSERT INTO ip_address_owners (ip_address, owner_name) VALUES
('192.168.2.10', 'Barbara Hart'),
('192.168.2.11', 'David Saugus'),
('192.168.2.12', 'Diego King'),
('192.168.2.40', 'Victoria Valencia')
;
-- Now join the IP address owner table to the IPv4 addresses.
SELECT rtv.ip_address, ipo.owner_name
FROM ip_address_ranges AS r,
TABLE(range_to_values(r.prefix, r.range_start::FLOAT, r.range_end::FLOAT)) AS rtv,
ip_address_owners AS ipo
WHERE ipo.ip_address = rtv.ip_address AND
r.prefix = '192.168.2' -- limits the output for this example
;
์ถ๋ ฅ:
+--------------+-------------------+
| IP_ADDRESS | OWNER_NAME |
+==============+===================+
| 192.168.2.10 | Barbara Hart |
+--------------+-------------------+
| 192.168.2.11 | David Saugus |
+--------------+-------------------+
| 192.168.2.12 | Diego King |
+--------------+-------------------+
| 192.168.2.40 | Victoria Valencia |
+--------------+-------------------+
์ฃผ์
์์ ์๋ ์ค๋ช ํ ๋๋ก ์๋ํฉ๋๋ค. ๊ทธ๋ฌ๋ UDTF๋ฅผ ์ค์ ์กฐ์ธ๊ณผ ๊ฒฐํฉํ ๋ ์ฃผ์ํด์ผ ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋น๊ฒฐ์ ์ ๋ฐ/๋๋ ์๊ธฐ์น ์์ ๋์์ด ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ํ, ์ด ๋์์ ํฅํ ๋ณ๊ฒฝ๋ ์ ์์ต๋๋ค.