【问题标题】:Hive multiple subqueries in WHERE predicate workaround在 WHERE 谓词解决方法中配置多个子查询
【发布时间】:2018-12-12 11:05:21
【问题描述】:

我有三个表,我想使用基于table1table2 的条件查询table3。以下是数据和查询的简化版本:

CREATE TABLE table1 (
  id int
);

INSERT INTO table1 VALUES(1);
INSERT INTO table1 VALUES(2);
INSERT INTO table1 VALUES(3);

+------------+--+
| table1.id  |
+------------+--+
| 1          |
| 2          |
| 3          |
+------------+--+

CREATE TABLE table2 (
  code varchar(10)
);

INSERT INTO table2 VALUES('a');
INSERT INTO table2 VALUES('b');
INSERT INTO table2 VALUES('c');

+--------------+--+
| table2.code  |
+--------------+--+
| a            |
| b            |
| c            |
+--------------+--+

CREATE TABLE table3 (
  id int,
  code varchar(10)
);

INSERT INTO table3 VALUES(1,'d');
INSERT INTO table3 VALUES(1,'a');
INSERT INTO table3 VALUES(2,'b');
INSERT INTO table3 VALUES(2,'e');
INSERT INTO table3 VALUES(4,'a');
INSERT INTO table3 VALUES(4,'d');

+------------+--------------+--+
| table3.id  | table3.code  |
+------------+--------------+--+
| 1          | d            |
| 1          | a            |
| 2          | b            |
| 2          | e            |
| 4          | a            |
| 4          | d            |
+------------+--------------+--+

基本上,我喜欢从table3 获取记录,前提是id 存在于table1 中并且code 不存在于table2 中。所以结果应该只是

1,d
2,e

以下查询不起作用:

SELECT * FROM table3 WHERE (table3.id IN (SELECT table1.id FROM
table1)) AND NOT (table3.code IN (SELECT table2.code FROM table2));

我收到了这个错误:

错误:编译语句时出错:FAILED: SemanticException [错误 10249]:第 1:94 行不受支持的子查询表达式“代码”:仅 支持 1 个子查询表达式。 (状态=42000,代码=10249)

独立地,每个条件都可以正常工作:

SELECT * FROM table3 WHERE (table3.id IN (SELECT table1.id FROM table1));

+------------+--------------+--+
| table3.id  | table3.code  |
+------------+--------------+--+
| 1          | d            |
| 1          | a            |
| 2          | b            |
| 2          | e            |
+------------+--------------+--+

SELECT * FROM table3 WHERE NOT (table3.code IN (SELECT table2.code FROM table2));

+------------+--------------+--+
| table3.id  | table3.code  |
+------------+--------------+--+
| 1          | d            |
| 2          | e            |
| 4          | d            |
+------------+--------------+--+

重要提示:我不能做 JOIN 或修改 FROM 中的任何内容,因为这是报告系统的一部分,所以我唯一能做的就是调整 WHERE 子句。

【问题讨论】:

    标签: sql hadoop select hive subquery


    【解决方案1】:

    您可以使用JOINs 重写它:

    SELECT DISTINCT t3.*
    FROM table3 t3
    JOIN table1 t1
      ON t3.id = t1.id
    LEFT JOIN table2 t2
      ON t2.code = t3.code
    WHERE t2.code IS NULL;
    

    DBFiddle Demo


    我唯一能做的就是调整 WHERE 子句。

    SELECT *
    FROM Table3 t
    WHERE EXISTS (SELECT 1
                  FROM table3 t3
                  JOIN table1 t1
                    ON t3.id = t1.id
                  LEFT JOIN table2 t2
                    ON t2.code = t3.code
                 WHERE t2.code IS NULL
                   AND t3.id = t.id
                   AND t3.code = t.code)
    

    DBFiddle Demo2

    【讨论】:

    • 您的第二个示例有效,但我仍在尝试了解它是如何做到的...介意给出一些解释吗?
    • @HP。当然。如您所见,第二个示例子查询与第​​一个示例完全相同。我相应地用JOIN and LEFT JOIN 替换了IN/NOT IN。然后你说你不能使用JOIN,但你只能操纵 WHERE 条件。所以我使用 EXISTS 子句和相关子查询。
    【解决方案2】:

    你可以使用的一个肮脏的技巧是交叉加入table1table2,因为无论如何你都不关心他们的关系,并使用exists 条件:

    SELECT *
    FROM   table3 
    WHERE  NOT EXISTS (SELECT     *
                       FROM       table1
                       CROSS JOIN table2
                       WHERE      table3.id = table1.id ON table3.code = table2.code)
    

    编辑:
    虽然上面的查询应该可以工作,但它的性能可能不会很好。一个稍快的变体是在子查询中使用union all

    SELECT *
    FROM   table3 
    WHERE  NOT EXISTS (SELECT     *
                       FROM       table1
                       WHERE      table3.id = table1.id 
                       UNION ALL
                       SELECT     *
                       FROM       table2
                       WHERE      table3.code = table2.code)
    

    【讨论】:

    • 我收到此错误:错误:编译语句时出错:失败:SemanticException 第 4:11 行子查询 sq_1 [ EXISTS (SELECT * FROM table1 WHERE table3.id = table1.id UNION ALL SELECT * FROM table2 WHERE table3.code = table2.code) ] 在第 3:11 行用作 sq_1:对于 Exists/Not Exists 运算符,子查询必须是相关的。 (状态=42000,代码=40000)
    • 第一个例子出错:Error: Error while compiling statement: FAILED: ParseException line 6:33 cannot recognize input near 'ON' 'table3' '.' in expression specification (state=42000,code=40000)
    【解决方案3】:

    NOT IN 是一种更简单的查询方式:

    SELECT t3.*
    FROM table3 t3
    WHERE t3.id IN (SELECT table1.id FROM table1) AND
          t3.code NOT IN (SELECT table2.code FROM table2);
    

    如果您仅限于一个子查询,这会变得很棘手。这是一种可能性,尽管我不确定 hive 是否会接受它:

    where exists (select 1
                  from table1 t1
                  where t1.id = t3.id and
                        not exists (select 1
                                    from table2 t2
                                    where t2.code = t3.code
                                   )
                 )
    

    你可以在没有双重嵌套的情况下做到这一点:

    where exists (select 1
                  from table1 t1 left join
                       table2 t2
                       on t2.code = t3.code
                  where t1.id = t3.id
                 )
    

    【讨论】:

    • used as sq_1 at Line 1:27: For Exists/Not Exists operator SubQuery must be Correlated. (state=42000,code=40000) 都出现了这个错误
    • @HP。 . . .所有子查询都是相关的。这是一条奇怪的消息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    • 2022-11-23
    • 1970-01-01
    • 2021-12-26
    相关资源
    最近更新 更多