在加入 SQL 查询时需要指导
Need guidance in joining SQL queries
列 - PCT_COL_IND 是 BOOLEAN 列。
SELECT ID,
MAX(CASE WHEN PCT_COL LIKE '%no-response%%' OR PCT_COL LIKE '%ind-not-found%'
OR PCT_COL LIKE '%search_res_not_found%' OR PCT_COL LIKE '%empty%' THEN 'TRUE' ELSE 'FALSE' END) AS PCT_COL_IND
FROM table1 A
LEFT JOIN table2 B
ON B.p_id = A.p_id
WHERE date = '2022-02-02'
GROUP BY ID
)
ID PCT_COL_IND
519181 FALSE
694562 FALSE
694892 FALSE
当我 运行 单独执行上述查询时,我得到的 PCT_COL_IND 值为 FALSE。
当我将上述查询与其他两个查询连接起来时,我得到的 PCT_COL_IND 值为 NULL。
我正在尝试使用 Snowflake 中的存储过程将源记录插入目标 table。
但是当我将上述查询与其他两个查询一起加入时,我得到的大部分记录都是 NULL 值
对于 PCT_COL_IND 列。我不应该显示 NULL 结果。
有人可以给我一些有逻辑的建议吗?
我在下面提到了整个查询:
SELECT distinct
a1.id,
a1.date,
a1.begin_time,
a1.Pno,
b1.PCT_COL_TXT,
b1.PCT_COL_IND,
CASE WHEN final.id is NULL then 'I' ELSE 'U' END as DML_Type
FROM(
SELECT
distinct id,
min(date) over (partition by id order by date) AS date ,
first_value(timestamp_col) over (partition by id order by cast(pno as int) nulls last) as begin_time,
first_value(pg_col) over (partition by id order by cast(pno as int) nulls last) as Pno,
row_number() over(partition by id order by date) as RNK
FROM table1
WHERE date = '2021-11-02'
QUALIFY RNK=1
)a1
left join
(
SELECT id,
CASE
WHEN PCT_COL LIKE '%no-response% then true
WHEN PCT_COL LIKE '%no-response%' then true
WHEN PCT_COL LIKE '%no-response% then true
WHEN PCT_COL LIKE '%no-response%' THEN 'TRUE'
ELSE 'FALSE' END AS PCT_COL_IND,
CASE WHEN listagg(DISTINCT PCT_COL ,',')WITHIN GROUP(ORDER BY PCT_COL )='' THEN NULL
ELSE REPLACE(lower(LISTAGG(DISTINCT PCT_COL , ',') WITHIN GROUP(ORDER BY PCT_COL )),'+','') END AS PCT_COL_TXT
FROM table1 B
LEFT JOIN table2
ON B.s_id = A.s_id
WHERE date = '2021-11-02'
GROUP BY 1,2
)b1
ON b1.id=a1.id
LEFT JOIN
(select distinct
id ,
cr_date,
begin_time,
Pno,
fin_pno,
PCT_COL_TXT,
PCT_COL_IND,
row_number() over(partition by id order by cr_date DESC) as RNK
FROM table4
QUALIFY RNK=1
)final on a1.id = final.id
WHERE (final.id is NULL)
or
(
nvl(a1.id,'0') <> nvl(final.id,'0' )
OR nvl(a1.date,'0')<> nvl(final.cr_date,'0')
OR nvl( a1.Pno,'NA') <> nvl(final.Pno,'NA')
OR nvl( a1.fin_pno,'NA') <> nvl(final.fin_pno,'NA')
OR nvl( b1.PCT_COL_TXT,'NA') <> nvl(final.PCT_COL_TXT,'NA')
OR nvl( b1.PCT_COL_IND,'0') <> nvl(final.PCT_COL_IND,'0')
)
我已经尝试了这个逻辑,但仍然得到 NULL 值。
首先,CASE 语句可以用不同的方式编写。正如你目前所拥有的那样,我认为它很难阅读。
SELECT
column1 as PCT_COL
,CASE WHEN PCT_COL LIKE '%no-response%%' OR PCT_COL LIKE '%ind-not-found%'
OR PCT_COL LIKE '%search_res_not_found%' OR PCT_COL LIKE '%empty%' THEN 'TRUE' ELSE 'FALSE' END as logic_1
,CASE
WHEN PCT_COL LIKE '%no-response%%' then true
WHEN PCT_COL LIKE '%ind-not-found%' then true
WHEN PCT_COL LIKE '%search_res_not_found%' then true
WHEN PCT_COL LIKE '%empty%' THEN 'TRUE'
ELSE 'FALSE'
END as logic_2
,PCT_COL LIKE ANY ('%no-response%%', '%ind-not-found%', '%search_res_not_found%', '%empty%') as logic_3
,NVL(PCT_COL LIKE ANY ('%no-response%%', '%ind-not-found%', '%search_res_not_found%', '%empty%'), FALSE) as logic_4
FROM VALUES
('not like any of these'),
('BLAHBLAHBLAH ind-not-found BLAH BLAH'),
(null);
第二个 CASE logic_2
同时拿更多 space 如果,你必须使用一个案例是流动更好的我的眼睛。但是我们可以做得更好,只需使用 LIKE ANY,如 logic_3 所示,但如果输入为 NULL
,则结果为 NULL,这有一个缺点,因此 NVL 会清理它,因为见于 logic_4
PCT_COL
LOGIC_1
LOGIC_2
LOGIC_3
LOGIC_4
'not like any of these'
FALSE
FALSE
FALSE
FALSE
'BLAHBLAHBLAH ind-not-found' BLAH BLAH
TRUE
TRUE
TRUE
TRUE
NULL
FALSE
FALSE
NULL
FALSE
所以这有助于指出你 NULL 的可能来源之一,与你离开加入有关,如果你只有 NULL 的 PCT_COL
你当前的代码不会给你 NULL 响应,所以这是不是你的问题。
您编写代码的下一件事是使用 MAX 聚合这些 TEXT 字符串。顺便说一句,使用 TEXT 字符串可能效率很低,但现在让我们忽略它。并查看 MAX 在不同输入下的表现。
SELECT column1 as ID, MAX(column2)
FROM VALUES
(1, 'TRUE'), (1, 'TRUE'),
(2, 'TRUE'), (2, 'FALSE'),
(3, 'TRUE'), (3, null),
(4, 'FALSE'), (4, 'FALSE'),
(5, 'FALSE'), (5, null),
(6, null), (6, null)
GROUP BY 1
ORDER BY 1;
ID
MAX(COLUMN2)
1
TRUE
2
TRUE
3
TRUE
4
FALSE
5
FALSE
6
NULL
因此,MAX 给出您不想要的结果 (NULL) 的唯一情况是,所有给定的输入都是 NULL。否则 'TRUE' 或 'FALSE' 字符串更好。
所以这表明您的 LEFT JOIN 不匹配,对于某些 ID,因此只产生 NULL 值。
所以你需要决定“你是否想要那些 NULL 值是因为 X”,此时你需要屏蔽它,我建议你将代码包装在 NVL(<expression>,FALSE)
中以找到这种边缘情况。
但与此同时,鉴于您正在获得您似乎不想要的 LEFT JOIN 结果。也许您不想要 LEFT JOIN。但考虑到这也是示例代码,您可能出于“其他原因”需要这些 LEFT JOIN。
所以我会使用:
SELECT
ID,
NVL(MAX(PCT_COL LIKE ANY ('%no-response%', '%ind-not-found%', '%search_res_not_found%', '%empty%')),false) AS PCT_COL_IND
FROM table1 A
LEFT JOIN table2 B
ON B.p_id = A.p_id
WHERE date = '2022-02-02'
GROUP BY ID
但是没有 PCT_COL_IND
的输出作为大写字符串,如果您真的需要,我会转到 IFF 并明确说明您在做什么:
SELECT
ID,
MAX(IFF(PCT_COL LIKE ANY ('%no-response%', '%ind-not-found%', '%search_res_not_found%', '%empty%'),'TRUE','FALSE')) AS PCT_COL_IND
FROM table1 A
LEFT JOIN table2 B
ON B.p_id = A.p_id
WHERE date = '2022-02-02'
GROUP BY ID
因此,要查看您的 SQL,可以简化为:
SELECT
a1.id
,b1.pct_col_ind
,CASE WHEN final.id is NULL then 'I' ELSE 'U' END as DML_Type
FROM (
SELECT
column1 as id
FROM VALUES
(1),
(2),
(3)
) AS a1
LEFT JOIN (
SELECT *
FROM VALUES
(1, true),
(2, true),
(3, false)
v(id, PCT_COL_IND)
) AS b1 ON a1.id = b1.id
LEFT JOIN (
SELECT *
FROM VALUES
--(1, true),
(2, true),
(3, false)
v(id, PCT_COL_IND)
) AS final ON a1.id = final.id
WHERE final.id is NULL
OR nvl(a1.id,'0') <> nvl(final.id,'0' )
OR nvl( b1.PCT_COL_IND,'0') <> nvl(final.PCT_COL_IND,'0')
;
我们只在 3 种情况下得到输出,其中 final 与 a1 行不匹配(这可能是由于在 final 中缺少一些 id 而触发的。所以让 a1 中有 3 个不在 final 中的 ID。和B1中有一个为真,一个为假,一个不存在。
现在我们得到输出的下一个原因是 a1.id != final.id
但假设我们加入它们是相等的,我们只会在 final.id 为 null 时才会在这里,因此我们已经触发了第一个 OR 或者如果A1 的 ID 中有空值,此时 a1.id 和 final.id 都为空,因此转换为 '0'
因此相等,因此这是一个毫无意义的子句,而不是我们的问题寻找。
所以第三个原因是将行添加到输出中。如果 nvl( b1.PCT_COL_IND,'0') <> nvl(final.PCT_COL_IND,'0')
。再次,如果右侧为空,我们已经进入,如果两边都为空,我们不会进入。因此这段代码表示如果我有一个值,并且 B1 上的左连接失败,那么 NVL 将使 b1.PCT_COL_IND -> '0'
所有的谈话将代码转换为:
SELECT
a1.id
,b1.pct_col_ind
,CASE WHEN final.id is NULL then 'I' ELSE 'U' END as DML_Type
FROM (
SELECT
column1 as id
FROM VALUES
(1),
(2),
(3),
(4),
(5)
) AS a1
LEFT JOIN (
SELECT *
FROM VALUES
(1, true)
,(2, false)
--,(3, false)
--,(4, true) /* we want to fail to match */
--,(5, true) /* we want to fail to match again */
v(id, PCT_COL_IND)
) AS b1 ON a1.id = b1.id
LEFT JOIN (
SELECT *
FROM VALUES
--(1, true),
--(2, true),
--(3, false)
(4, true),
(5, false)
v(id, PCT_COL_IND)
) AS final ON a1.id = final.id
WHERE final.id is NULL
--OR nvl(a1.id,'0') <> nvl(final.id,'0' )
OR nvl( b1.PCT_COL_IND,'0') <> nvl(final.PCT_COL_IND,'0')
;
ID
PCT_COL_IND
DML_TYPE
1
TRUE
I
2
FALSE
I
3
NULL
I
4
NULL
U
因此第 5 行不存在,因为 final.PCT_COL_IND 为假,并且 b1.PCT_COL_IND 的空值被替换为文本字符串“0”,隐式转换为假布尔值,因此行被丢弃。在这里我们开始看到使用字符串与布尔值的影响也许你毕竟想要字符串。
但是第 4 行存在,因为 final.pct_col_ind 为真,这与空字符串不同
存在第 1、2、3 行,因为它们不在最终结果中,但“在 b1 中没有结果”,因此第 3 行为空。
但是你的 b1 和 a1 来自相同的数据,所以这种情况不应该发生。但这就是我触发案例 4 的方式。所以现在我很困惑。我可能得再考虑一下..
列 - PCT_COL_IND 是 BOOLEAN 列。
SELECT ID,
MAX(CASE WHEN PCT_COL LIKE '%no-response%%' OR PCT_COL LIKE '%ind-not-found%'
OR PCT_COL LIKE '%search_res_not_found%' OR PCT_COL LIKE '%empty%' THEN 'TRUE' ELSE 'FALSE' END) AS PCT_COL_IND
FROM table1 A
LEFT JOIN table2 B
ON B.p_id = A.p_id
WHERE date = '2022-02-02'
GROUP BY ID
)
ID PCT_COL_IND
519181 FALSE
694562 FALSE
694892 FALSE
当我 运行 单独执行上述查询时,我得到的 PCT_COL_IND 值为 FALSE。
当我将上述查询与其他两个查询连接起来时,我得到的 PCT_COL_IND 值为 NULL。 我正在尝试使用 Snowflake 中的存储过程将源记录插入目标 table。
但是当我将上述查询与其他两个查询一起加入时,我得到的大部分记录都是 NULL 值 对于 PCT_COL_IND 列。我不应该显示 NULL 结果。
有人可以给我一些有逻辑的建议吗?
我在下面提到了整个查询:
SELECT distinct
a1.id,
a1.date,
a1.begin_time,
a1.Pno,
b1.PCT_COL_TXT,
b1.PCT_COL_IND,
CASE WHEN final.id is NULL then 'I' ELSE 'U' END as DML_Type
FROM(
SELECT
distinct id,
min(date) over (partition by id order by date) AS date ,
first_value(timestamp_col) over (partition by id order by cast(pno as int) nulls last) as begin_time,
first_value(pg_col) over (partition by id order by cast(pno as int) nulls last) as Pno,
row_number() over(partition by id order by date) as RNK
FROM table1
WHERE date = '2021-11-02'
QUALIFY RNK=1
)a1
left join
(
SELECT id,
CASE
WHEN PCT_COL LIKE '%no-response% then true
WHEN PCT_COL LIKE '%no-response%' then true
WHEN PCT_COL LIKE '%no-response% then true
WHEN PCT_COL LIKE '%no-response%' THEN 'TRUE'
ELSE 'FALSE' END AS PCT_COL_IND,
CASE WHEN listagg(DISTINCT PCT_COL ,',')WITHIN GROUP(ORDER BY PCT_COL )='' THEN NULL
ELSE REPLACE(lower(LISTAGG(DISTINCT PCT_COL , ',') WITHIN GROUP(ORDER BY PCT_COL )),'+','') END AS PCT_COL_TXT
FROM table1 B
LEFT JOIN table2
ON B.s_id = A.s_id
WHERE date = '2021-11-02'
GROUP BY 1,2
)b1
ON b1.id=a1.id
LEFT JOIN
(select distinct
id ,
cr_date,
begin_time,
Pno,
fin_pno,
PCT_COL_TXT,
PCT_COL_IND,
row_number() over(partition by id order by cr_date DESC) as RNK
FROM table4
QUALIFY RNK=1
)final on a1.id = final.id
WHERE (final.id is NULL)
or
(
nvl(a1.id,'0') <> nvl(final.id,'0' )
OR nvl(a1.date,'0')<> nvl(final.cr_date,'0')
OR nvl( a1.Pno,'NA') <> nvl(final.Pno,'NA')
OR nvl( a1.fin_pno,'NA') <> nvl(final.fin_pno,'NA')
OR nvl( b1.PCT_COL_TXT,'NA') <> nvl(final.PCT_COL_TXT,'NA')
OR nvl( b1.PCT_COL_IND,'0') <> nvl(final.PCT_COL_IND,'0')
)
我已经尝试了这个逻辑,但仍然得到 NULL 值。
首先,CASE 语句可以用不同的方式编写。正如你目前所拥有的那样,我认为它很难阅读。
SELECT
column1 as PCT_COL
,CASE WHEN PCT_COL LIKE '%no-response%%' OR PCT_COL LIKE '%ind-not-found%'
OR PCT_COL LIKE '%search_res_not_found%' OR PCT_COL LIKE '%empty%' THEN 'TRUE' ELSE 'FALSE' END as logic_1
,CASE
WHEN PCT_COL LIKE '%no-response%%' then true
WHEN PCT_COL LIKE '%ind-not-found%' then true
WHEN PCT_COL LIKE '%search_res_not_found%' then true
WHEN PCT_COL LIKE '%empty%' THEN 'TRUE'
ELSE 'FALSE'
END as logic_2
,PCT_COL LIKE ANY ('%no-response%%', '%ind-not-found%', '%search_res_not_found%', '%empty%') as logic_3
,NVL(PCT_COL LIKE ANY ('%no-response%%', '%ind-not-found%', '%search_res_not_found%', '%empty%'), FALSE) as logic_4
FROM VALUES
('not like any of these'),
('BLAHBLAHBLAH ind-not-found BLAH BLAH'),
(null);
第二个 CASE logic_2
同时拿更多 space 如果,你必须使用一个案例是流动更好的我的眼睛。但是我们可以做得更好,只需使用 LIKE ANY,如 logic_3 所示,但如果输入为 NULL
,则结果为 NULL,这有一个缺点,因此 NVL 会清理它,因为见于 logic_4
PCT_COL | LOGIC_1 | LOGIC_2 | LOGIC_3 | LOGIC_4 |
---|---|---|---|---|
'not like any of these' | FALSE | FALSE | FALSE | FALSE |
'BLAHBLAHBLAH ind-not-found' BLAH BLAH | TRUE | TRUE | TRUE | TRUE |
NULL | FALSE | FALSE | NULL | FALSE |
所以这有助于指出你 NULL 的可能来源之一,与你离开加入有关,如果你只有 NULL 的 PCT_COL
你当前的代码不会给你 NULL 响应,所以这是不是你的问题。
您编写代码的下一件事是使用 MAX 聚合这些 TEXT 字符串。顺便说一句,使用 TEXT 字符串可能效率很低,但现在让我们忽略它。并查看 MAX 在不同输入下的表现。
SELECT column1 as ID, MAX(column2)
FROM VALUES
(1, 'TRUE'), (1, 'TRUE'),
(2, 'TRUE'), (2, 'FALSE'),
(3, 'TRUE'), (3, null),
(4, 'FALSE'), (4, 'FALSE'),
(5, 'FALSE'), (5, null),
(6, null), (6, null)
GROUP BY 1
ORDER BY 1;
ID | MAX(COLUMN2) |
---|---|
1 | TRUE |
2 | TRUE |
3 | TRUE |
4 | FALSE |
5 | FALSE |
6 | NULL |
因此,MAX 给出您不想要的结果 (NULL) 的唯一情况是,所有给定的输入都是 NULL。否则 'TRUE' 或 'FALSE' 字符串更好。
所以这表明您的 LEFT JOIN 不匹配,对于某些 ID,因此只产生 NULL 值。
所以你需要决定“你是否想要那些 NULL 值是因为 X”,此时你需要屏蔽它,我建议你将代码包装在 NVL(<expression>,FALSE)
中以找到这种边缘情况。
但与此同时,鉴于您正在获得您似乎不想要的 LEFT JOIN 结果。也许您不想要 LEFT JOIN。但考虑到这也是示例代码,您可能出于“其他原因”需要这些 LEFT JOIN。
所以我会使用:
SELECT
ID,
NVL(MAX(PCT_COL LIKE ANY ('%no-response%', '%ind-not-found%', '%search_res_not_found%', '%empty%')),false) AS PCT_COL_IND
FROM table1 A
LEFT JOIN table2 B
ON B.p_id = A.p_id
WHERE date = '2022-02-02'
GROUP BY ID
但是没有 PCT_COL_IND
的输出作为大写字符串,如果您真的需要,我会转到 IFF 并明确说明您在做什么:
SELECT
ID,
MAX(IFF(PCT_COL LIKE ANY ('%no-response%', '%ind-not-found%', '%search_res_not_found%', '%empty%'),'TRUE','FALSE')) AS PCT_COL_IND
FROM table1 A
LEFT JOIN table2 B
ON B.p_id = A.p_id
WHERE date = '2022-02-02'
GROUP BY ID
因此,要查看您的 SQL,可以简化为:
SELECT
a1.id
,b1.pct_col_ind
,CASE WHEN final.id is NULL then 'I' ELSE 'U' END as DML_Type
FROM (
SELECT
column1 as id
FROM VALUES
(1),
(2),
(3)
) AS a1
LEFT JOIN (
SELECT *
FROM VALUES
(1, true),
(2, true),
(3, false)
v(id, PCT_COL_IND)
) AS b1 ON a1.id = b1.id
LEFT JOIN (
SELECT *
FROM VALUES
--(1, true),
(2, true),
(3, false)
v(id, PCT_COL_IND)
) AS final ON a1.id = final.id
WHERE final.id is NULL
OR nvl(a1.id,'0') <> nvl(final.id,'0' )
OR nvl( b1.PCT_COL_IND,'0') <> nvl(final.PCT_COL_IND,'0')
;
我们只在 3 种情况下得到输出,其中 final 与 a1 行不匹配(这可能是由于在 final 中缺少一些 id 而触发的。所以让 a1 中有 3 个不在 final 中的 ID。和B1中有一个为真,一个为假,一个不存在。
现在我们得到输出的下一个原因是 a1.id != final.id
但假设我们加入它们是相等的,我们只会在 final.id 为 null 时才会在这里,因此我们已经触发了第一个 OR 或者如果A1 的 ID 中有空值,此时 a1.id 和 final.id 都为空,因此转换为 '0'
因此相等,因此这是一个毫无意义的子句,而不是我们的问题寻找。
所以第三个原因是将行添加到输出中。如果 nvl( b1.PCT_COL_IND,'0') <> nvl(final.PCT_COL_IND,'0')
。再次,如果右侧为空,我们已经进入,如果两边都为空,我们不会进入。因此这段代码表示如果我有一个值,并且 B1 上的左连接失败,那么 NVL 将使 b1.PCT_COL_IND -> '0'
所有的谈话将代码转换为:
SELECT
a1.id
,b1.pct_col_ind
,CASE WHEN final.id is NULL then 'I' ELSE 'U' END as DML_Type
FROM (
SELECT
column1 as id
FROM VALUES
(1),
(2),
(3),
(4),
(5)
) AS a1
LEFT JOIN (
SELECT *
FROM VALUES
(1, true)
,(2, false)
--,(3, false)
--,(4, true) /* we want to fail to match */
--,(5, true) /* we want to fail to match again */
v(id, PCT_COL_IND)
) AS b1 ON a1.id = b1.id
LEFT JOIN (
SELECT *
FROM VALUES
--(1, true),
--(2, true),
--(3, false)
(4, true),
(5, false)
v(id, PCT_COL_IND)
) AS final ON a1.id = final.id
WHERE final.id is NULL
--OR nvl(a1.id,'0') <> nvl(final.id,'0' )
OR nvl( b1.PCT_COL_IND,'0') <> nvl(final.PCT_COL_IND,'0')
;
ID | PCT_COL_IND | DML_TYPE |
---|---|---|
1 | TRUE | I |
2 | FALSE | I |
3 | NULL | I |
4 | NULL | U |
因此第 5 行不存在,因为 final.PCT_COL_IND 为假,并且 b1.PCT_COL_IND 的空值被替换为文本字符串“0”,隐式转换为假布尔值,因此行被丢弃。在这里我们开始看到使用字符串与布尔值的影响也许你毕竟想要字符串。
但是第 4 行存在,因为 final.pct_col_ind 为真,这与空字符串不同
存在第 1、2、3 行,因为它们不在最终结果中,但“在 b1 中没有结果”,因此第 3 行为空。
但是你的 b1 和 a1 来自相同的数据,所以这种情况不应该发生。但这就是我触发案例 4 的方式。所以现在我很困惑。我可能得再考虑一下..