![](/img/trans.png)
[英]dbt Jinja macro to pass set of columns to a list and perform calculations and renaming
[英]dbt macro: How to join tables on multiple columns in a loop
我正在編寫一個 dbt model 來連接多個列上的兩個表,編譯為如下所示:
SELECT
A.col1,
A.col2,
A.col3,
FROM
A
LEFT JOIN
B
ON
(A.col1 = B.col1 OR (IS_NAN(A.col1) AND IS_NAN(B.col1))
AND (A.col2 = B.col2 OR (IS_NAN(A.col2) AND IS_NAN(B.col2))
AND (A.col3 = B.col3 OR (IS_NAN(A.col3) AND IS_NAN(B.col3))
這個邏輯將應用於許多表對,所以我需要一個宏。 所有列的連接邏輯都是相同的,因此在 ON 子句中的列上循環將是完美的,就像這樣
SELECT
{% for col in all_cols %}
A.{{ col }},
{% endfor %}
FROM
A
LEFT JOIN
B
ON
{% for col in all_cols %}
(A.{{col}} = B.{{col}} OR (IS_NAN(A.{{col}}) AND IS_NAN(B.{{col}})),
<-- What to put here for AND the next condition???
{% endfor %}
遍歷列時,如何將 ON 子句中的條件與AND
連接?
您的示例查詢缺少)
首先生成一個數據集Test
和兩個表A
和B
CREATE OR REPLACE TABLE
Test.B AS
SELECT
IF
(RAND()>0.5,NULL,RAND()) col1,
IF
(RAND()>0.5,NULL,RAND()) col2,
IF
(RAND()>0.5,NULL,RAND()) col3
FROM
UNNEST(GENERATE_ARRAY(1,100)) a
然后在同一區域運行此查詢,如果不是美國則必須手動設置。
DECLARE col_list ARRAY<STRING> ;
DECLARE col_list_A STRING ;
DECLARE col_list_B STRING ;
DECLARE col_list_on STRING ;
EXECUTE IMMEDIATE
"Select array_agg(column_name) from Test.INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='A'" INTO col_list;
EXECUTE IMMEDIATE
"Select STRING_AGG(concat('A.',cols)) FROM UNNEST(?) cols" INTO col_list_A USING col_list;
EXECUTE IMMEDIATE
"Select STRING_AGG(concat('B.',cols)) FROM UNNEST(?) cols" INTO col_list_B USING col_list;
EXECUTE IMMEDIATE
"Select STRING_AGG(concat('(A.',cols,' = B.',cols,' OR (IS_NAN(A.',cols,') AND IS_NAN(B.',cols,')) ) '),' AND ') FROM UNNEST(?) cols" INTO col_list_on USING col_list;
EXECUTE IMMEDIATE
"SELECT " || col_list_A || "," || col_list_B || " FROM Test.A LEFT JOIN Test.B ON " || col_list_on
首先DECLARE
所有變量。 然后查詢表A
的列名到變量col_list
。 使用concat
構建A.col1, A.col2...
列表,然后也構建B.
.。 concat
再次用於ON
條件。
最后將所有變量放入查詢中。
我想警告說,這個最終查詢在較大的表上表現不佳。 如果這對您來說是個問題,請隨意提出另一個問題,並提供有關您目標的更多詳細信息。
可愛的方式(添加一個始終為真的謂詞,因此您可以使用AND
開始每個語句):
SELECT
{% for col in all_cols %}
A.{{ col }},
{% endfor %}
FROM
A
LEFT JOIN
B
ON
1=1
{% for col in all_cols %}
AND (A.{{col}} = B.{{col}} OR (IS_NAN(A.{{col}}) AND IS_NAN(B.{{col}})))
{% endfor %}
不那么可愛的方法,使用loop.first
( loop
是 jinja 在 for 循環中設置的一個變量,它有一些方便的屬性loop.first
和loop.last
特別有用):
SELECT
{% for col in all_cols %}
A.{{ col }},
{% endfor %}
FROM
A
LEFT JOIN
B
ON
{% for col in all_cols %}
{% if not loop.first %}AND{% endif %} (A.{{col}} = B.{{col}} OR (IS_NAN(A.{{col}}) AND IS_NAN(B.{{col}})))
{% endfor %}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.