SQL加入ID和日期

时间:2016-11-04 14:20:02

标签: sql postgresql join

我对如何基于日期和sku执行连接感到有点困惑。

我有3个表,其中一个包含订单信息,一个包含订单项,另一个包含费用

我可以加入订单项和订单信息以获取以下内容:

Sku    | Price  | Date
------ | ------ | -----
ABC1   | 3.99   | 2016-11-01
ABC2   | 2.99   | 2016-10-01
ABC1   | 3.99   | 2016-10-01
ABC3   | 5.99   | 2016-11-01

我需要根据订单日期加入货物的成本

这位于费用表中,如下所示:

Sku    | Cost   | Valid_from | Valid_to
------ | ------ | ---------- | ----------
ABC1   | 1.99   | 2016-11-01 | NULL
ABC2   | 0.99   | 2015-10-01 | NULL
ABC1   | 2.99   | 2015-10-01 | 2016-10-30 
ABC3   | 3.99   | 2015-11-01 | 2016-10-30 

某些skus有几个成本记录,有开始和结束日期,其他有一个开始日期,没有结束日期。

我努力查找sku,然后寻找相应的日期

Sku    | Price  | Date       | Cost
------ | ------ | ---------- | -----
ABC1   | 3.99   | 2016-11-01 | 1.99
ABC2   | 2.99   | 2016-10-01 | 0.99
ABC1   | 3.99   | 2016-10-01 | 2.99
ABC3   | 5.99   | 2016-11-01 | 3.99

我可能会尝试过它,但似乎无法加入这些并获取相关信息。

任何有用的帮助

3 个答案:

答案 0 :(得分:2)

您可以动态创建日期范围,然后测试订单项中的日期是否属于该范围:

select li.*, c.cost
from line_item li
  join cost c on li.sku = c.sku 
             and li.date <@ daterange(c.valid_from, c.valid_to);

使用NULL作为范围的上限会自动使其成为无限范围,因此无需在查询中明确处理NULL

在线示例:http://rextester.com/OAJ69387

日期范围内的索引可能会加快速度:

create index on cost using gist (daterange(valid_from, valid_to));

注意:

对于您的示例数据,上述查询将返回包含SKU ABC3的订单项的费用信息,因为该订单项的日期不属于费用行定义的范围ABC3。如果您的样本数据是正确的,并且您确实需要包含订单项ABC3,则需要外部联接 - 但是您不会有成本价值。

答案 1 :(得分:0)

您需要在范围内的日期。但在这种情况下,您需要两个条件来处理开放范围。

 SELECT io.*, c.Cost
 FROM itemOrder io
 JOIN costs c
   ON io.Sku =  c.Sku
  AND ( (io.Date >= c.Valid_from  and c.Valid_to IS NULL)
     OR (io.Date >= c.Valid_from  and io.Date <= c.Valid_to)
      )                                    -- ^^ this may need to be `<`
                                           -- depend on how you define your ranges

答案 2 :(得分:0)

Valid_To列显然是多余的,我强烈建议将其从表中删除。

要获取订单日期的最新价格,请使用交叉申请前1个查询:

select o.sku, o.price, o.date, cx.cost
from order o
cross join lateral
(
  select cost 
  from  costs c
  where c.sku = o.sku and c.valid_from <= o.date
  order by date desc
  limit 1
) cx;