按适当的时间段加入表格

时间:2011-12-15 17:52:52

标签: sql postgresql join

在postgresql数据库中,我有2个像这样的表:

表项目:

item_id    item     save_date (date dd/mm/yy)
----------------------------------------------
1          car       01/12/11
2          wheel     10/12/11
3          screen    11/12/11
4          table     15/12/11

表期间:

period_id  period_name    start (date dd/mm/yy)
------------------------------------------------
1          period1      05/12/11
2          period2      09/12/11
3          period3      12/12/11

所以我想得到一个联接表,在表项中添加最合适的句点(如果匹配)。如果项目的save_date位于期间的开始日期之后,则期间将匹配。

例如对于“car”,日期是01/12/2011,所以我进入表格期间,我可以看到所有期间都在该日期之后开始,所以我必须将其设置为空。如果我选择“屏幕”,那么日期是11/12/11所以在我应该使用期间2期间,因为它是最新匹配的。

因此,连接表将导致:

item_id    item     save_date   period_name
----------------------------------------------
1          car       01/12/11      null
2          wheel     10/12/11      period2
3          screen    11/12/11      period2
4          table     15/12/11      period3

进行此加入的最佳方式是什么?

由于

2 个答案:

答案 0 :(得分:2)

交叉申请或共同相关的子查询将有效。

Sub Query方法,因为Cross Apply仅适用于SQL Server 2005(UnTested)

SELECT Item_Id,
       Item,
       Save_Date,
       (
        SELECT MAX(Period_Name)
          FROM Periods
         WHERE Start = (
                SELECT MAX(start) MaxStart 
                  FROM periods P 
                 WHERE I.Save_Date > P.start)
       ) AS Period_Name  
 FROM ITEMS I

答案 1 :(得分:2)

SET search_path='tmp';

DROP TABLE items CASCADE;
CREATE TABLE items
    ( item_id INTEGER NOT NULL PRIMARY KEY
    , item VARCHAR
    , save_date date NOT NULL
    );
INSERT INTO items(item_id,item,save_date) VALUES
 ( 1, 'car', '2011-12-01' )
,( 2, 'wheel', '2011-12-10' )
,( 3, 'screen', '2011-12-11' )
,( 4, 'table', '2011-12-15' )
    ;

DROP TABLE periods CASCADE;
CREATE TABLE periods
    ( period_id INTEGER NOT NULL PRIMARY KEY
    , period_name VARCHAR
    , start_date date NOT NULL
    );
INSERT INTO periods(period_id,period_name,start_date) VALUES
 ( 1, 'period1', '2011-12-05' )
,( 2, 'period2', '2011-12-09' )
,( 3, 'period3', '2011-12-12' )
    ;
-- self-join to find the next interval
WITH pe AS (
    SELECT p0.period_id,p0.period_name,p0.start_date
        , p1.start_date AS end_date
    FROM periods p0
    -- must be a left join; because the most recent interval is still open
    -- (has no successor)
    LEFT JOIN periods p1 ON p1.start_date > p0.start_date
    WHERE NOT EXISTS (
        SELECT * FROM periods px
        WHERE px.start_date > p0.start_date
        AND px.start_date < p1.start_date
        )
    )
SELECT it.item_id
    , it.item
    , it.save_date
    , pe.period_id
    , pe.period_name
    , pe.start_date
    , pe.end_date
FROM items it
LEFT JOIN pe
       ON it.save_date >= pe.start_date
      AND ( it.save_date < pe.end_date OR pe.end_date IS NULL)
    ;

结果:

 item_id |  item  | save_date  | period_id | period_name | start_date |  end_date
---------+--------+------------+-----------+-------------+------------+------------
       1 | car    | 2011-12-01 |           |             |            |
       2 | wheel  | 2011-12-10 |         2 | period2     | 2011-12-09 | 2011-12-12
       3 | screen | 2011-12-11 |         2 | period2     | 2011-12-09 | 2011-12-12
       4 | table  | 2011-12-15 |         3 | period3     | 2011-12-12 |
(4 rows)