2016-11-04 109 views
1

我对如何执行基于日期和sku的连接有点难住。SQL加入ID和日期

我有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 

我可能尝试过工程师,但似乎无法得到接近加盟这些并取回相关信息。

任何帮助appriciated

+0

对于SKU行项目'ABC3'没有相应的成本项(2016年11月1日之后是ABC3的成本范围的结束)。因此,无论您的预期输出是错误的还是样本数据。 –

回答

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)); 

注:

为了您的样本数据,上面的查询将不是返回成本信息由于该行项目的日期不属于ABC3的成本行定义的范围,因此需要使用SKU ABC3对行项目进行定价。如果您的示例数据是正确的,并且您确实希望包含订单项ABC3,则需要外部联合 - 但您不需要成本值。

+0

寻找日期范围教程索引应该看起来像CREATE INDEX cars_price_range_idx ON汽车使用要点(成本); '和你写的一样吗?看起来在'cost'列上创建一个'GIST'索引就足够了 –

+0

@JuanCarlosOropeza:'cost'列的索引是完全没有用的。但你是对的,它应该是一个主要指标。 –

+0

对不起,我的意思是日期栏。我看到的例子是在一些范围之间的成本,并且该指数在成本列中。我认为现在会创建一个'范围'索引。 –

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 
+0

基本上应该是马回答相同的结果,但他使用'datarange'我不知道。 –

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; 
+0

There在Postgres中不是'交叉应用'。它使用SQL标准的“交叉连接横向”。我不同意'valid_to'是多余的:它可以用来创建约束来防止重叠的有效期间 –

+0

@a_horse_with_no_name:哦,谢谢。我将编辑... –

+0

为什么你说'valid_to'是多余的? –