Join 配置单元:非等左联接的变通方法

Join 配置单元:非等左联接的变通方法,join,hive,left-join,Join,Hive,Left Join,配置单元不支持非相等联接:常见的解决方法是将联接条件移动到where子句,当需要内部联接时,该子句可以正常工作。但是左会合呢 人为的例子。假设我们有一个orderLineItem表,我们需要连接到一个ProductPrice表,该表具有productID、price和price适用的日期范围。我们想加入其中,其中ProductID=ProductID&OrderDate介于开始日期和结束日期之间。如果productID或有效日期范围不匹配,我仍然希望查看所有orderLineItems 此SQL

配置单元不支持非相等联接:常见的解决方法是将联接条件移动到where子句,当需要内部联接时,该子句可以正常工作。但是左会合呢

人为的例子。假设我们有一个orderLineItem表,我们需要连接到一个ProductPrice表,该表具有productID、price和price适用的日期范围。我们想加入其中,其中ProductID=ProductID&OrderDate介于开始日期和结束日期之间。如果productID或有效日期范围不匹配,我仍然希望查看所有orderLineItems

此SQL FIDLE是我们如何在MSSQL中执行此操作的示例:

问题 如果我应用典型的解决方法,并将非equi过滤器移动到where子句,它将成为一个内部联接。在上面的例子中,在sqlfiddle和下面的例子中,我有一个不在查找中的产品ID

问题: 如果配置单元不支持非eqi连接,如何实现左非eqi连接

[SQLFiddle内容]

表:

CREATE TABLE OrderLineItem(
  LineItemIDId int IDENTITY(1,1),
  OrderID int  NOT NULL,
  ProductID int NOT NULL,
  OrderDate Date
);


CREATE TABLE ProductPrice(
  ProductID int,
  Cost float,
  startDate  Date,
  EndDate  Date


);
加载数据&我们如何加入MSSQL:

--Old Price. Should be ignored
INSERT INTO ProductPrice(ProductID, COST,startDate,EndDate) VALUES  (1, 50,'12/1/2012','1/1/2013');
INSERT INTO ProductPrice(ProductID, COST,startDate,EndDate) VALUES (2, 55,'12/1/2012','1/1/2013');

--Price for Order 2. Should be applied to Order 1
INSERT INTO ProductPrice (ProductID, COST,startDate,EndDate) VALUES(1, 20,'12/1/2013','1/1/2014');
INSERT INTO ProductPrice (ProductID, COST,startDate,EndDate) VALUES(2, 25,'12/1/2013','1/1/2014');

--Price for Order 2. Should be applied to Order 2
INSERT INTO ProductPrice (ProductID, COST,startDate,EndDate) VALUES(1, 15,'1/2/2014','3/1/2014');
INSERT INTO ProductPrice (ProductID, COST,startDate,EndDate) VALUES(2, 20,'1/2/2014','3/1/2014');


--January 1st 2014 Order
INSERT INTO OrderLineItem(OrderID,ProductID,OrderDate) VALUES (1, 1,'1/1/2014') ;
INSERT INTO OrderLineItem(OrderID,ProductID,OrderDate) VALUES (1, 2,'1/1/2014');

--Feb 1st 2014 Order
INSERT INTO OrderLineItem(OrderID,ProductID,OrderDate) VALUES (2, 1,'2/1/2014');
INSERT INTO OrderLineItem (OrderID,ProductID,OrderDate) VALUES(2, 2,'2/1/2014');
INSERT INTO OrderLineItem (OrderID,ProductID,OrderDate) VALUES(2, 3,'2/1/2014'); -- no price

SELECT * FROM OrderLineItem;

SELECT * FROM OrderLineItem li LEFT OUTER JOIN  ProductPrice p on
p.ProductID=li.ProductID AND  OrderDate BETWEEN  startDate AND  EndDate;
  • 创建具有添加的序列行号的左表副本:

    CREATE TABLE OrderLineItem_serial AS
    SELECT ROW_NUMBER() OVER() AS serial, * FROM OrderLineItem;
    
    备注:对于某些表格格式(必须无压缩),这可能更有效:

  • 进行内部联接:

    CREATE TABLE OrderLineItem_inner AS
    SELECT * FROM OrderLineItem_serial li JOIN ProductPrice p
    on p.ProductID = li.ProductID WHERE OrderDate BETWEEN startDate AND EndDate;
    
  • 通过序列左连接:

    SELECT * FROM OrderLineItem_serial li
    LEFT OUTER JOIN OrderLineItem_inner i on li.serial = i.serial;
    

  • Hive 0.10支持交叉联接,因此您可以在WHERE子句中处理所有的“θ联接”(非等联接)条件。

    为什么不使用WHERE子句来分别允许空情况

    SELECT * FROM OrderLineItem li 
    LEFT OUTER JOIN  ProductPrice p 
    ON p.ProductID=li.ProductID 
    WHERE ( StartDate IS NULL OR OrderDate BETWEEN startDate AND EndDate);
    

    这应该会解决问题-如果左连接匹配,它将使用日期逻辑,如果不匹配,它将像左连接一样保持空值不变。

    不确定是否可以避免使用双连接:

    SELECT * 
    FROM OrderLineItem li 
    LEFT OUTER JOIN  (
      SELECT p.*
      FROM ProductPrice p
      JOIN OrderLineItem li 
      ON p.ProductID=li.ProductID 
      WHERE OrderDate BETWEEN StartDate AND EndDate ) p
    ON p.ProductId = li.ProductID
    WHERE StartDate IS NULL OR 
      OrderDate BETWEEN StartDate AND EndDate;
    

    这样,如果存在匹配且StartDate不为null,则必须存在有效的开始/结束日期匹配。

    对于延迟,我感到抱歉-我有几个问题:我在配置单元上。10-没有窗口函数。连接中使用的第二个查询,我的配置单元版本不支持该查询(我的原始问题)。谢谢你!1.试着使用concat…作为序列号,而不是row_number…作为序列号,如第1项和第2项下面的备注所述。我更改了第二个查询。由于它是一个内部联接,您可以在where子句中设置BEVERY条件。如果产品id上有匹配项,但所有匹配项的开始/结束范围都在订单日期之外,那么如何处理?在这种情况下,您将过滤掉该行,从而将理论上的外部联接转换为一个查询,该查询可以输出比OrderLineItem少的行
    SELECT * 
    FROM OrderLineItem li 
    LEFT OUTER JOIN  (
      SELECT p.*
      FROM ProductPrice p
      JOIN OrderLineItem li 
      ON p.ProductID=li.ProductID 
      WHERE OrderDate BETWEEN StartDate AND EndDate ) p
    ON p.ProductId = li.ProductID
    WHERE StartDate IS NULL OR 
      OrderDate BETWEEN StartDate AND EndDate;