【问题标题】:How can I generate a new row out of two other rows in Postgres?如何从 Postgres 的另外两行中生成新行?
【发布时间】:2012-06-04 15:11:30
【问题描述】:

我在 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) 在新生成的行中,苹果应该始终排在第一位,橙色排在第二位。

2) 始终将 apple 和 orange 行与最接近的日期时间配对,并忽略其他行。

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

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 中执行此操作?

【问题讨论】:

  • 正好两个 fuits - apple / orange?没有其他也没有NULL?
  • @Erwin Brandstetter 同一张桌子上还有一些其他水果,但对于本报告,我只需要找到苹果和橙子。
  • @ErwinBrandstetter 好的,这次你做 CTE,好吗?
  • @wildplasser:你明白了。 stackoverflow.com/a/10884184/939860
  • +1 顺便说一句,让自己非常清楚。

标签: sql postgresql


【解决方案1】:

日期时间始终按升序排列,大多数情况下苹果行首先插入,橙色排在第二位,但我必须捕捉并消除一些例外情况。

如果我没听错的话,你想知道是否有连续两行有相同的水果,对吧?

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

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;

用简单的英语:将每一行与下一行连接起来(其中“下一个”的含义由datetime 排序决定)并检查它们的结果是否匹配。你可以在这个SQL Fiddle玩它。

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

【讨论】:

  • OP 明确表示他想要apple,然后是orange two consecutive rows with the same fruit
  • @ErwinBrandstetter 苹果后面跟橙色不能跟苹果。他想要检测到两个连续的水果,这样他就可以“消除”它们。我不清楚他是否希望通过从表中删除或只是通过从查询结果中省略它们来消除它们 - 我的回答应该对前一种情况有所帮助。
【解决方案2】:

具有 CTE 和窗口函数的解决方案:

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 的列的语法。

【讨论】:

  • 我知道 OP 希望匹配最近的时间戳,而不是最近的 ID?但它确实非常紧凑。
  • @wildplasser:在这种情况下也是如此,因为:The datetime is always in ascending order
【解决方案3】:
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

【讨论】:

    【解决方案4】:
    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)
    

    【讨论】:

      猜你喜欢
      • 2015-08-05
      • 1970-01-01
      • 2023-04-10
      • 2021-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-25
      • 2013-01-07
      相关资源
      最近更新 更多