多个连接在一个SQL查询中

时间:2012-07-13 04:46:09

标签: join group-by sql-order-by hql hive

以下是TestingTable1中按日期降序排列的数据

BUYER_ID  |   ITEM_ID       |  CREATED_TIME
----------+-----------------+----------------------
1345653      110909316904     2012-07-09 21:29:06
1345653      151851771618     2012-07-09 19:57:33
1345653      221065796761     2012-07-09 19:31:48
1345653      400307563710     2012-07-09 18:57:33

如果这是TestingTable2中的以下数据,按日期降序排序

USER_ID  |   PRODUCT_ID    |    LAST_TIME
---------+----------------+-----------------------
1345653     110909316904      2012-07-09 22:29:06
1345653     150851771618      2012-07-09 19:57:33    

TestingTable1中的每一行都应与TestingTable2匹配,如果不匹配或者TestingTable2中没有数据,那么我需要在输出中显示它们,如TestingTable1我所知有这个数据,但对应TestingTable2我有这个数据(这将是错误的数据),所以我可以看到什么是不匹配和缺少什么数据。

我需要在TestingTable2TestingTable1上将BUYER_IDUSER_ID进行比较。我需要看一下,如果BUYER_IDUSER_ID匹配,那么我需要将ITEM_IDPRODUCT_IDCREATED_TIMELAST_TIME进行比较,如果有的话与TestingTable2中的任何一个或两者中的TestingTable1进行比较后,TestingTable1不匹配,那么我需要显示结果。

因此,如果你看一下上面的例子 - 基本上我有三个场景

  1. 首先 - 在ITEM_ID中,第一行PRODUCT_IDTestingTable2的第一行中的CREATED_TIME匹配,但LAST_TIMETestingTable1不匹配{1}}表示两个表中的第一行
  2. 其次 - 在CREATED_TIME中,第二行LAST_TIMETestingTable2第二行中的ITEM_ID匹配但PRODUCT_IDTestingTable1不匹配{1}}表示两个表中的第二行
  3. 第三 - 在TestingTable2中,TestingTable2中的最后两行(行)根本不存在。我编写的查询中未涉及此方案。我也希望在我的查询中使用此方案
  4. 因此,在将TestingTable1TestingTable1进行比较时,我需要涵盖这三个案例。 TestingTable1是MAIN表,通过该表总是需要进行比较,这意味着TestingTable2中的数据始终是准确的。

    所以我需要显示下面的结果,如果不匹配其中任何一个,或者数据不在TestingTable1中的所有 - TestingTable2数据,那么它旁边就是{{} 1}}数据,以便我可以看到TestingTable1TestingTable2相比有什么价值

    BUYER_ID   |   ITEM_ID       |    CREATED_TIME           |      USER_ID   |     PRODUCT_ID     |     LAST_TIME   
    -----------+-----------------+---------------------------+----------------+--------------------+-----------------------
    1345653      110909316904       2012-07-09 21:29:06            1345653          110909316904      2012-07-09 22:29:06
    1345653      151851771618       2012-07-09 19:57:33            1345653          150851771618      2012-07-09 19:57:33
    1345653      221065796761       2012-07-09 19:31:48            NULL             NULL              NULL
    1345653      400307563710       2012-07-09 18:57:33            NULL             NULL              NULL
    

    下面是我编写的查询,其中仅涵盖了我上面提到的two scenarios,它工作正常,我将得到上面的输出,从输出中留下最后两行。但我需要在此(下面)查询中添加third scenario,以便它提供如上所述的输出。

    SELECT *
    FROM   (SELECT T2.buyer_id,
                   T2.item_id,
                   T2.created_time AS created_time,
                   subq.user_id,
                   subq.product_id,
                   subq.LAST_TIME
            FROM   TestingTable2 subq
                   JOIN TestingTable1 T2
                     ON T2.buyer_id = subq.user_id
                        AND subq.LAST_TIME = ( T2.created_time )
            WHERE  ( subq.product_id <> T2.item_id )
            UNION ALL
            SELECT T2.buyer_id,
                   T2.item_id AS item_id,
                   T2.created_time,
                   subq.user_id,
                   subq.product_id AS product_id,
                   subq.LAST_TIME
            FROM   TestingTable2 subq
                   JOIN TestingTable1 T2
                     ON T2.buyer_id = subq.user_id
                        AND subq.product_id = T2.item_id
            WHERE  ( subq.LAST_TIME <> ( T2.created_time ) )) finalResult
    ORDER  BY finalResult.BUYER_ID;
    

    任何建议都将受到赞赏。

    P.S。我在过去几天里几乎没有问过与JOIN相关的问题,但这只涉及我的两个场景,而不是我在此查询中需要的第三个场景。

    更新: - 我不能对SQL使用NOT INNOT EXISTS语法,因为我正在使用Hive而Hive不支持NOT INNOT EXISTS,因此我需要其他方式来处理有这个。

    我只需要使用我的查询来修改它以适用于Third Scenario,因为Hive将支持SQL语法。

    下面是我的 SQL Fiddle ,它完成了我上面的两个场景,但不是第三个场景。任何人都可以帮我修改我的查询以便为第三种情况工作吗?

    http://sqlfiddle.com/#!3/102dd/1/0

    表1中的数据应该在表2中,如果不存在,那么我需要在从Table1进行比较后显示数据之间的不匹配,并且有可能表1中的数据不在表2中,我也希望表明这一点。

    更新了小提琴的输出http://sqlfiddle.com/#!3/102dd/3/0

    BUYER_ID   |   ITEM_ID       |    CREATED_TIME           |      USER_ID   |     PRODUCT_ID     |     LAST_TIME   
    -----------+-----------------+---------------------------+----------------+--------------------+-----------------------
    1345653       151851771618      July, 09 2012 19:57:33      1345653            150851771618         July, 09 2012 19:57:33
    1345653       221065796761      July, 09 2012 19:31:48      1345653            221165796761         July, 09 2012 19:31:48
    1345653       110909316904      July, 09 2012 21:29:06      1345653            110909316904         July, 09 2012 22:29:06
    1345653       400307563710      July, 09 2012 18:57:33      NULL               NULL                 NULL
    1345653       310411560125      July, 09 2012 16:09:49      NULL               NULL                 NULL
    

    更新SQL错误导致错误

    我用此查询替换了TestingTable1 -

    (SELECT BUYER_ID, ITEM_ID, rank(BUYER_ID), CREATED_TIME
    FROM (
        SELECT BUYER_ID, ITEM_ID, CREATED_TIME
        FROM testingtable1
        where to_date(from_unixtime(cast(UNIX_TIMESTAMP(CREATED_TIME) as int))) = '2012-07-09'
        DISTRIBUTE BY BUYER_ID
        SORT BY BUYER_ID, CREATED_TIME desc
    ) T1
    WHERE rank(BUYER_ID) < 5)
    

    TestingTable2使用此查询 -

    (SELECT USER_ID, PROD_AND_TS.PRODUCT_ID as PRODUCT_ID, PROD_AND_TS.TIMESTAMPS as TIMESTAMPS FROM testingtable2 lateral view explode(PURCHASED_ITEM) exploded_table as PROD_AND_TS where to_date(from_unixtime(cast(PROD_AND_TS.TIMESTAMPS as BIGINT))) = '2012-07-09')
    

4 个答案:

答案 0 :(得分:2)

如果由于DBMS限制而无法使用NOT IN@eggyal发布的干净解决方案,则另一个选项可能是完全复制原始联合并在{{1}中使用这些结果}。

应用于您的sqlFiddle,以下语句将返回所需的结果。

SQL声明

LEFT JOIN

答案 1 :(得分:1)

尝试用SQL编写的这段代码。我已经在SQL Fiddle上测试了这个。

 SELECT 
 tt1.buyer_id,tt1.item_id,tt1.created_time,
 tt2.user_id,tt2.product_id,tt2.last_time
 FROM 
 testingtable1 tt1 LEFT OUTER JOIN
 testingtable2 tt2 ON
 tt1.buyer_id = tt2.user_id
 AND 
 tt1.item_id = tt2.product_id
 AND
 tt1.created_time = tt2.last_time

答案 2 :(得分:1)

此答案是对您的评论请求的回应:https://stackoverflow.com/a/11440651/1166147 我实际上已经在你的其他2个重复项中给出了这个答案,它创建了你显示的确切输出。这是我在这里写的第一个查询: https://stackoverflow.com/a/11440539/1166147 它在这里提到并解释了两次: https://stackoverflow.com/a/11398990/1166147

我将您的查询修改回我的并在您的SQLFiddle中运行它:

enter image description here

您的要求已经发展,如果TestingTable1确实始终是准确的数据,您现在可以只执行LEFT JOIN

SELECT *
FROM TestingTable1 A
LEFT JOIN TestingTable2 B ON A.BUYER_ID = B.USER_ID AND (B.LAST_TIME = A.Created_TIME  OR B.PRODUCT_ID = A.ITEM_ID)

编辑评论

MOCK SCENARIOS

SCENARIO||       TABLE1           ||           TABLE2
----------------------------------------------------------
SCENARIO||  BUYER  ITEM      TIME ||  USER   PRODUCT  TIME
1       ||    1     A        09   ||   1     Z        09
2       ||    1     B        10   ||   NO RECORD IN TABLE 2
3       ||    1     C        10   ||   1     C        02
4       ||    1     D        12   ||   NO RECORD IN TABLE 2
5       ||    1     E        01   ||   1     E        01
6       ||   NO RECORD IN TABLE 1 ||   1     Y        05      

您要求的是SQL解决方案 - 但这不是一个SQL问题。您排除了给您的有效SQL答案,因为您无法在您的环境中使用它们,然后再次重新打开相同的问题。这是一个HQL / HIVE问题。是的,有一些相似之处,但存在一些差异。

看起来HQL会支持这样的东西,虽然我无法测试,而SQLFiddle也无法对此进行测试。您必须弄清楚如何在HQL中执行ISNULLCOALESCE,如select *旁边的注释所示。如果那里存在非空值,这将“合并”结果并从非空的值返回值。我相信HQL支持ISNULL:

select * --BUYER_ID, isNull(B.USER_ID,C.USER_ID)
from
(select BUYER_ID,ITEM_ID ,Created_TIME  from TestingTable1) a
left join
(SELECT USER_ID,PRODUCT_ID, last_time
  FROM TestingTable2 ) b on(a.BUYER_ID = b.user_id and B.last_time =   A.Created_TIME)
left join
(SELECT USER_ID,PRODUCT_ID, last_time
  FROM TestingTable2 ) c on(a.BUYER_ID = c.user_id and c.PRODUCT_ID = A.ITEM_ID)

这是另一个可能给你一些想法的TSQL答案。我永远不会在TSQL中使用它,但实际上它可以工作。

SELECT A.BUYER_ID,A.ITEM_ID,CREATED_TIME,COALESCE(B.USER_ID,X.USER_ID,Y.USER_ID),
COALESCE(B.PRODUCT_ID,X.PRODUCT_ID,Y.PRODUCT_ID)
,COALESCE(B.last_time,X.last_time,Y.last_time)
FROM TestingTable1 A
LEFT JOIN TestingTable2 B ON A.BUYER_ID = B.USER_ID AND B.PRODUCT_ID = A.ITEM_ID
AND B.last_time = A.Created_TIME
LEFT JOIN( SELECT USER_ID,PRODUCT_ID, last_time
  FROM TestingTable1 A
  LEFT JOIN TestingTable2 B ON A.BUYER_ID = B.USER_ID AND B.last_time = A.Created_TIME 
  WHERE  ISNULL(B.PRODUCT_ID,0) <> A.ITEM_ID AND B.USER_ID IS NOT NULL) X ON
  X.USER_ID = A.BUYER_ID AND A.Created_TIME = X.last_time
LEFT JOIN( SELECT USER_ID,PRODUCT_ID, last_time
FROM TestingTable1 A
LEFT JOIN TestingTable2 B ON A.BUYER_ID = B.USER_ID AND ISNULL( B.PRODUCT_ID,0) =   A.ITEM_ID  
WHERE  B.last_time <> A.Created_TIME AND B.USER_ID IS NOT NULL) Y ON
A.BUYER_ID = Y.USER_ID AND A.ITEM_ID = Y.PRODUCT_ID

答案 3 :(得分:0)

听起来你正在寻找的是全外连接。我没有在你的帖子中看到你正在使用什么类型的数据库,所以我无法发布确切的语法,但是这个链接可能指向正确的方向:

http://www.w3resource.com/sql/joins/perform-a-full-outer-join.php

具体看底部的图表。