为啥当缺少连接字段之一时,HIVE 中的完全外部连接会给出奇怪的结果?

Posted

技术标签:

【中文标题】为啥当缺少连接字段之一时,HIVE 中的完全外部连接会给出奇怪的结果?【英文标题】:Why does full outer join in HIVE gives weird result when one of the join fields is missing?为什么当缺少连接字段之一时,HIVE 中的完全外部连接会给出奇怪的结果? 【发布时间】:2016-10-14 20:00:32 【问题描述】:

我正在比较 SQL 引擎之间的行为。 Oracle 具有我所期望的 SQL 引擎完全外连接的行为:

甲骨文

CREATE TABLE sql_test_a 
( 
    ID         VARCHAR2(4000 BYTE), 
    FIRST_NAME VARCHAR2(200 BYTE), 
    LAST_NAME  VARCHAR2(200 BYTE) 
); 

CREATE TABLE sql_test_b 
( 
    NUM         VARCHAR2(4000 BYTE), 
    FIRST_NAME VARCHAR2(200 BYTE), 
    LAST_NAME  VARCHAR2(200 BYTE) 
); 

INSERT INTO sql_test_a (ID, FIRST_NAME, LAST_NAME) VALUES ('1', 'John', 'Snow'); 

INSERT INTO sql_test_a (ID, FIRST_NAME, LAST_NAME) VALUES ('2', 'Mike', 'Tyson'); 


INSERT INTO sql_test_b (NUM, FIRST_NAME, LAST_NAME) VALUES ('20', 'Mike', 'Tyson'); 

当我执行以下操作时,它给了我预期的结果。结果表包含两行,其中一行包含NULLNUM 字段,因为表sql_test_b 中没有john snow。

SELECT A.FIRST_NAME, A.LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B
ON 
A.FIRST_NAME = B.FIRST_NAME 
AND
A.LAST_NAME = B.LAST_NAME;

你可以在这里测试sql脚本:http://sqltest.net/

蜂巢

但是,在 HIVE 中,如果您要尝试相同的操作,则完全外连接会生成一个包含两行的表。应该是“John Snow”行的行包含字段 FIRST_NAME、LAST_NAME 和 NUM 的 NULL1 填写为ID,仅此而已。

为什么在 HIVE 中有这种奇怪的行为?这是一个错误吗?或者我错过了什么...因为 Oracle 11g 似乎处理得更好。谢谢。

【问题讨论】:

【参考方案1】:

我无法模拟@Candic3 报告的结果

我使用了以下语句以及与问题中相同的“选择”查询。

CREATE TABLE IF NOT EXISTS sql_test_a (ID String, FIRST_NAME String, LAST_NAME  String) COMMENT 'sql_test_a'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;


CREATE TABLE IF NOT EXISTS sql_test_b (NUM String, FIRST_NAME String, LAST_NAME  String) COMMENT 'sql_test_b'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;


INSERT INTO sql_test_a VALUES ('1', 'John', 'Snow');
INSERT INTO sql_test_a VALUES ('2', 'Mike', 'Tyson');
INSERT INTO sql_test_b VALUES ('20', 'Mike', 'Tyson');

SELECT A.FIRST_NAME, A.LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B
ON 
A.FIRST_NAME = B.FIRST_NAME 
AND
A.LAST_NAME = B.LAST_NAME;

请查看附件中的结果。

但是,由于未注意到的小错误,例如 DDL 与实际数据(例如,来自平面文件)之间的数据类型不匹配或 DDL 中提到的分隔符与实际数据中的分隔符不匹配,选择查询将返回 NULL .

【讨论】:

【参考方案2】:

我认为“(”之后的问题与传统 sql 略有不同。

        SELECT A.FIRST_NAME, A.LAST_NAME, A.ID, B.NUM
                 FROM
                  SQL_TEST_A A
                     FULL OUTER JOIN
               SQL_TEST_B B ON 
             (A.FIRST_NAME = B.FIRST_NAME AND A.LAST_NAME = B.LAST_NAME);

【讨论】:

【参考方案3】:

在选择语句中,您使用了 A.FIRST_NAME、A.LAST_NAME,这对于表 B 中的行不存在。这就是 null 值的原因。而是使用 COALESCE 在 A.FIRST_NAME 和 B.FIRST_NAME 之间查找非空值

SELECT COALESCE(A.FIRST_NAME, B.FIRST_NAME) as FIRST_NAME, COALESCE(A.LAST_NAME, B.LAST_NAME) as LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B
ON 
A.FIRST_NAME = B.FIRST_NAME 
AND
A.LAST_NAME = B.LAST_NAME;

【讨论】:

以上是关于为啥当缺少连接字段之一时,HIVE 中的完全外部连接会给出奇怪的结果?的主要内容,如果未能解决你的问题,请参考以下文章

当单个字段是 GROUP BY 中的多个字段之一时,如何汇总该字段的数据?

当 UDF 使用一些外部资源文件但在本机运行时,为啥 Hive 错误 FileNotFoundException?

BGP动态路由协议

Python - 使用 JayDeBeApi 连接到 Hive 时出错

Hive 外部表架构重新连接

大数据之Hive:hive中的cross join函数