【问题标题】:Multi Join in a single SQL query单个 SQL 查询中的多连接
【发布时间】:2012-07-13 04:46:08
【问题描述】:

以下是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我有这个数据(这将是错误的数据),这样我就可以看到什么不匹配,什么数据丢失了。

我需要在BUYER_IDUSER_ID 上比较TestingTable2TestingTable1。我需要看看,如果BUYER_IDUSER_ID 匹配,那么我需要将ITEM_IDPRODUCT_IDCREATED_TIMELAST_TIME 进行比较,如果TestingTable2 在与@987654342 比较后不匹配@ 在其中一个或两个中,然后我需要显示结果。

所以如果你看上面的例子——我基本上有三个场景

  1. 首先- 在TestingTable1 中,第一行ITEM_IDTestingTable2 第一行中的PRODUCT_ID 匹配,但CREATED_TIME 与两个表中第一行的LAST_TIME 不匹配
  2. 其次-在TestingTable1中,第二行CREATED_TIMETestingTable2第二行中的LAST_TIME匹配,但ITEM_ID与两个表中第二行的PRODUCT_ID不匹配
  3. 第三 - 在TestingTable1 中,最后两行(行)在TestingTable2 中根本不存在。我写的查询中没有涵盖这种情况。我希望这种情况也出现在我的查询中

所以这是我在比较TestingTable2TestingTable1 时需要涵盖的三种情况。而TestingTable1是MAIN表,需要一直进行比较,这意味着TestingTable1中的数据总是准确的。

因此,如果不匹配其中任何一个或TestingTable2 中根本没有数据-TestingTable1 数据然后在它旁边相同的TestingTable2 数据,我需要显示如下所示的结果,所以我可以看到 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;

任何建议将不胜感激。

附:在过去的几天里,我问了一些与 JOIN 相关的问题,但这仅涵盖了我的两个场景,而不是我在此查询中需要的第三个场景。

更新:- 我不能对 SQL 使用 NOT INNOT EXISTS 语法,因为我正在使用 Hive 并且 Hive 不支持 NOT INNOT EXISTS 所以我需要一些其他方法来处理这个问题。

我只需要使用我的查询来修改它以适用于第三场景,因为这样 Hive 将支持 SQL 语法。

下面是我的SQL Fiddle,它满足了我上面的两个场景,但不是第三种场景。谁能帮我修改我的查询以适用于第三种情况?

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

Table1中的数据应该在Table2中,如果没有,那么我需要在与Table1比较后显示数据之间的不匹配,也有可能,Table1中的数据不会出现在Table2中,我也想证明这一点。

小提琴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')

【问题讨论】:

  • 同一个(user,item) 对是否会在任一表中出现多次?
  • 这两个表将始终按 created_time 的降序排序。并且这两个表都将仅包含同一日期的数据。 (刚才表格是这样的,它只是实时的)。 Table1 中的每一行都应该在 Table2 中,所以可能是我上面提到的所有三种情况。不,它们不会出现超过一次。
  • 看你的fiddle,我修改了数据,结果输出错误,http://sqlfiddle.com/#!3/102dd/3/0,你没看懂我的问题,Table1中的数据应该在Table2中,如果没有,那么我需要在与 Table1 进行比较后显示数据之间的不匹配,并且有可能 Table1 中的数据不会出现在 Table2 中,我也想显示这一点。如果你看看我的输出。
  • 基本上 Table1 中的每一行都应该与 Table2 匹配,就像 Table1 中的第一行应该与 Table2 中的第一行一样,可能 ITEM_ID 和 PRODUCT_ID 不匹配,TIME 会匹配,也是可能的 ITEM_ID 和 PRODUCT_ID 将匹配,但 TIME 将不匹配。所以我需要显示对应表1的输出我有这个数据,但是表2中的相同数据是这个(这是错误的数据)。尝试从我给你的 SQL fiddle 上的问题中运行我的查询。你会更好地了解我在寻找什么。我的 SQL 查询适用于我的任务中的两种情况。
  • this 怎么样?

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


【解决方案1】:

如果由于 DBMS 限制,您不能使用 NOT IN@eggyal 发布的干净解决方案,另一种选择可能是完全复制您的原始联合并在 LEFT JOIN 中使用这些结果。

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

SQL 语句

SELECT * 
FROM(
    SELECT *
    FROM TestingTable1 A
    JOIN TestingTable2 B ON A.BUYER_ID = B.USER_ID AND B.LAST_TIME = A.Created_TIME 
    WHERE B.PRODUCT_ID <> A.ITEM_ID
    UNION ALL
    SELECT * 
    FROM TestingTable1 A
    INNER JOIN TestingTable2 B ON A.BUYER_ID = B.USER_ID AND B.PRODUCT_ID = A.ITEM_ID  
    WHERE B.LAST_TIME <> A.Created_TIME      
 ) X
UNION ALL
SELECT A.*, NULL, NULL, NULL
FROM   TestingTable1 A
       LEFT OUTER JOIN (
            SELECT *
            FROM TestingTable1 A
            JOIN TestingTable2 B ON A.BUYER_ID = B.USER_ID AND B.LAST_TIME = A.Created_TIME 
            WHERE B.PRODUCT_ID <> A.ITEM_ID
            UNION ALL
            SELECT * 
            FROM TestingTable1 A
            INNER JOIN TestingTable2 B ON A.BUYER_ID = B.USER_ID AND B.PRODUCT_ID = A.ITEM_ID  
            WHERE B.LAST_TIME <> A.Created_TIME      
       ) X ON A.BUYER_ID = X.BUYER_ID AND A.ITEM_ID = X.ITEM_ID
WHERE  X.BUYER_ID IS NULL

【讨论】:

  • 感谢 Lieven 的出色回答,您的查询在 SQL 中运行良好,为了在 HiveQL 中运行,我需要将 TestingTable1 和 TestingTable2 替换为一些 SQL 查询,因此我将 TestingTable1 替换为一些 SQL 查询,将 TestingTable2 替换为一些 SQL 查询,然后当我尝试在 Hive 中运行时,I got some ambiguous columns name error。你能看看我在那个 SQL 查询中做错了什么吗?它正在发生一些列名
  • 我无法执行你的实际语句(而且我怀疑你会为它创建一个小提琴:) 但是对于这样的错误,我会使用除法和征服技术。我将从删除联合的前半部分开始,看看语句是否运行。如果没有,请删除另一个联合并查看它是否运行。重复这个直到你得到一个可运行的语句。然后错误将来自语句的最后一个删除部分。
  • X UNION ALL 上面这个查询有效并且在这个查询有效之后,但是当我一起运行它时,它就不起作用了。我已经编辑了我的问题,将我用两张表替换的内容。我猜可能是因为你可以帮助我。
  • @rjchar - 如果将SELECT A.*, NULL, NULL, NULL 替换为SELECT A.*, NULL AS User_ID, NULL AS Product_ID, NULL AS Laste_Time 会怎样
  • 不,它抱怨一些不同的错误知道..FAILED: Error in semantic analysis: Schema of both sides of union should match: Column user_id is of type bigint on first table and type void on second table
【解决方案2】:

试试这段用 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

【讨论】:

  • 这也不起作用,这会返回我根本不需要的输出。 :(。这是存在数据的 SQL 小提琴,我们需要一些 sql 查询来提供我在问题中显示的输出。http://sqlfiddle.com/#!3/fe795/1/0
  • 这是我最新的 SQL 小提琴,我的查询也在那里,它只满足我的两个场景,但不满足第三个场景。 http://sqlfiddle.com/#!3/102dd/1/0.
  • 查看http://sqlfiddle.com/#!3/102dd/2/0 提出您的查询后我得到的输出。这是错误的,如果您将问题中的输出与您的输出进行比较,您会看到差异。在这我摆弄我添加了更多的数据。
【解决方案3】:

此答案是为了回应您在此处发表评论的请求:https://stackoverflow.com/a/11440651/1166147
实际上,我已经在您的其他 2 个副本中为您提供了答案,这些副本创建了您所显示的确切输出。这是我在这里写的第一个查询: https://stackoverflow.com/a/11440539/1166147 它在这里被提及和解释了两次: https://stackoverflow.com/a/11398990/1166147

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

不过,您的要求已经发生了变化,如果 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)

编辑以征求意见

模拟场景

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 * 旁边的 cmets 所示。如果那里有非空值,这将“合并”结果并返回非空值。我确实相信 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

【讨论】:

  • 虽然这在 SQL 中有效。但它在 HiveQL 中不起作用,因为 Hive 不支持 OR in JOIN,所以这就是我需要其他方法来解决这个问题的原因。任何建议。
  • 已编辑 - 但您需要停止重新打开它 - 特别是作为 SQL 问题。它是 HQL,虽然有相似之处,但也存在差异,你让人们花时间在上面,然后说他们的有效 SQL 答案对 SQL 不起作用 - 当他们起作用时。
【解决方案4】:

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

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

具体看下图。

【讨论】:

  • 我正在使用 Hive 并且 Hive 支持类似 SQL 的语法,所以我猜任何 sql 语法都可以工作,但我需要在上面的查询中添加该功能,因为上面的查询对我来说很好以上两种情况。
  • 如果是这样,我会尝试这样的事情: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 FULL OUTER JOIN TestingTable1 T2 ON T2.buyer_id = subq.user_id AND T2.item_id = subq.product_id AND T2.CREATED_TIME = subq.LAST_TIME 对不起,我忘了添加完整的外部联接
  • 我尝试了上面的查询,我使用这个查询得到的输出,我不需要那个输出。我在每一行前面都得到了 NULL。我需要上述格式的输出。
  • 哦,我相信我误解了你的问题,我以为如果 table1 没有匹配项,你想查看 table2 中的记录;如果 table2 没有匹配项,则查看 table 1 中的记录,如果它们都匹配。如果您只想始终查看 table1,并且仅在页面中间有匹配项(否则显示 null)时才显示表 2,那就是左连接或右外连接(取决于您如何编写它)。
  • 如果你看到我刚刚添加的这个 sql fiddle,http://sqlfiddle.com/#!3/d8a67/3/0。我也需要这样,但我需要在我的 SQL 查询中添加这个东西,因为我只需要使用单个查询来显示它。
猜你喜欢
  • 2012-04-27
  • 1970-01-01
  • 1970-01-01
  • 2017-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-31
相关资源
最近更新 更多