如何从Postgres中的另外两行生成一个新行?

时间:2012-06-04 15:11:31

标签: sql postgresql

我在Postgres表中有一些如下所示的数据:

1 apple datetime1
2 orange datetime2
3 apple datetime3
4 orange datetime4
5 apple datetime5
6 orange datetime6
.

日期时间始终按升序排列,大多数时候苹果行首先插入,橙色第二次,除了我必须捕获和消除的一些例外。

我实际需要的是Postgres查询,它只会配对苹果和橙子:

1 apple datetime1 2 orange datetime2
3 apple datetime3 4 orange datetime4
5 apple datetime5 6 orange datetime6

苹果不应与其他苹果配对,橙子不应与其他橙子配对。

有几个条件:

1)在新生成的行中,apple应始终为first,橙色为second。

2)始终将苹果和橙色行与最近的日期时间配对,并忽略其他行。

例如,如果我的原始数据如下所示:

1 apple datetime1
2 apple datetime2
3 orange datetime3
4 orange datetime4

2 apple datetime2 3 orange datetime3

并忽略行

1 apple datetime1
4 orange datetime4

如何在Postgres中做到这一点?

4 个答案:

答案 0 :(得分:2)

  

日期时间始终按升序排列,大多数时候苹果行首先插入,橙色第二次,除了我必须捕获和消除的一些例外。

如果我理解正确,你想找到连续两行是否有相同的水果,对吗?

如果是这样,你可以这样做:

WITH Q AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY datetime) R
    FROM YOUR_TABLE
)
SELECT *
FROM Q Q1 JOIN Q Q2 ON Q1.R = Q2.R - 1
WHERE Q1.fruit = Q2.fruit;

用简单的英语:将每一行加入下一行(其中“next”的含义由datetime排序确定),并检查它们的水果是否匹配。您可以在此SQL Fiddle中使用它。

BTW,这不是一个好的数据库设计。您应该考虑重新设计,因此上面描述的“无效”情况自然会被数据库结构本身阻止。

答案 1 :(得分:1)

CTE& amp; amp; amp;窗口功能:

WITH x AS (
    SELECT *
          ,lead(tbl) OVER (ORDER BY id) AS y
    FROM tbl
    )
SELECT x.id,     x.fruit,   x.dt
     , (y).id, (y).fruit, (y).dt
FROM   x
WHERE  fruit = 'apple'
AND    (y).fruit = 'orange'
ORDER  BY x.id;

也可以作为子查询完成,但每request from @wildplasser。 :)

我为每个窗口函数lead()选择整个“下一行”。请注意带括号的语法,以访问复合(行)类型y的列。

答案 2 :(得分:0)

select 
    t0.id, t0.fruit, t0.datetime, 
    t1.id, t1.fruit, t1.datetime
from t t0
inner join t t1 on 
    t0.fruit = 'apple' 
    and 
    t1.fruit = 'orange'
    and
    t0.datetime < t1.datetime
order by t1.datetime - t0.datetime
limit 1

答案 3 :(得分:0)

SET search_path='lutser';

DROP TABLE fruits;
CREATE TABLE fruits
    ( id INTEGER NOT NULL
    , fruit varchar
    , zdate varchar
    );  
INSERT INTO fruits(id,fruit,zdate)
VALUES

(1, 'apple', 'datetime01')
, (2, 'orange', 'datetime02')
, (3, 'apple', 'datetime03')
, (4, 'orange', 'datetime04')
, (5, 'apple', 'datetime05')
, (6, 'orange', 'datetime06')
, (11, 'apple', 'datetime11')
, (12, 'apple', 'datetime12')
, (13, 'orange', 'datetime13')
, (14, 'orange', 'datetime14')
    ;

SELECT fa.id, fa.fruit, fa.zdate
    , fo.id, fo.fruit, fo.zdate
FROM fruits fa
JOIN fruits fo ON fa.zdate < fo.zdate
WHERE fa.fruit = 'apple' AND fo.fruit = 'orange'
AND NOT EXISTS (
    SELECT *
    FROM fruits nx
    WHERE nx.fruit = 'orange'
    AND nx.zdate > fa.zdate
    AND nx.zdate < fo.zdate
    )   
AND NOT EXISTS (
    SELECT *
    FROM fruits nx
    WHERE nx.fruit = 'apple'
    AND nx.zdate < fo.zdate
    AND nx.zdate > fa.zdate
    )   
    ;

结果:

DROP TABLE
CREATE TABLE
INSERT 0 10
 id | fruit |   zdate    | id | fruit  |   zdate    
----+-------+------------+----+--------+------------
  1 | apple | datetime01 |  2 | orange | datetime02
  3 | apple | datetime03 |  4 | orange | datetime04
  5 | apple | datetime05 |  6 | orange | datetime06
 12 | apple | datetime12 | 13 | orange | datetime13
(4 rows)