比较PostgreSQL中每个Id的不同行

时间:2014-10-31 02:27:49

标签: sql postgresql greatest-n-per-group amazon-redshift

我表中的几列似乎是

Id   Code   date        latest
1    T     2014-10-04    0
2    B     2014-10-19    0
2    B     2014-10-26    0
1    S     2014-10-05    0
1    T     2014-10-06    0
1    T     2014-10-08    1
2    P     2014-10-27    1

我正在跟踪每个ID所做的所有更改。如果有任何更改,我会插入新行并更新最新值列。

我想要的是每个Id,我应该能够找到最新为0的最后一个代码。此外,该代码不应该等于现有代码(latest = 1)所以对于id = 1,answer不能< / p>

 Id   Code
 1    T

至于id = 1 T是现有代码(latest = 1) 理想情况下,我的输出应该如下:

Id    Code
 1     S
 2     B

我想我可以为latest = 0

中的每个ID获取代码的最新值

但是我如何确保它不应该等于现有代码值(latest = 1

3 个答案:

答案 0 :(得分:0)

我认为以下是您想要的:

select t.*
from (select distinct on (code) id, code
      from table t
      where latest = 0
      order by code, date desc
     ) t
where not exists (select 1 from table t2 where t2.id = t.id and t2.code = t.code and t2.latest = 1);

答案 1 :(得分:0)

我相信您应该拥有当前版本的数据,并且您应该创建另一个表,您可以在其中存储以前的修订版,具有Id的外键。您的Id无法满足具有此名称的列的一般期望。所以,理想情况下,你会:

  • 创建一个表Revisions(Id, myTableId, core, date, revision),其中Idauto_increment primary keymyTableId将指向记录的Id(1和示例中的2)
  • 将元素迁移到修订版:insert into Revisions(myTableId, core, date, revision) select Id, core, date latest from MyTable where latest = 0
  • 更新已迁移的记录:update Revisions r1 set r1.revision = (select count(*) from revisions r2 where r2.date < r1.date)
  • 从新表中删除旧数据:delete from MyTable where latest = 0
  • 从MyTable
  • 中删除latest

从这里,您将始终可以选择倒数第二个版本,或倒数第二个等等,没有问题。请注意,我的代码建议在postgreSQL中可能是错误的语法,因为我从未使用它,但是这个想法也应该在那里工作。

答案 2 :(得分:0)

适用于 Postgres

SELECT DISTINCT ON (t0.id)
       t0.id, t0.code
FROM   tbl t0
LEFT   JOIN tbl t1 ON t1.code = t0.code
                  AND t1.id = t0.id
                  AND t1.latest = 1
WHERE  t0.latest = 0
AND    t1.code IS NULL
ORDER  BY t0.id, t0.date DESC;

我使用LEFT JOIN / IS NULL的组合删除latest = 1行的兄弟。有多种方法可以做到这一点:

DISTINCT ON的详细信息:

具有CTE和2x LEFT JOIN的版本

由于 Redshift 似乎不支持DISTINCT ON

WITH cte AS (
   SELECT t0.*
   FROM   tbl t0
   LEFT   JOIN tbl t1 ON t1.code = t0.code
                     AND t1.id = t0.id
                     AND t1.latest = 1
   WHERE  t0.latest = 0
   AND    t1.id IS NULL
   )
SELECT c0.id, c0.code
FROM   cte c0
LEFT   JOIN cte c1 ON c1.id = c0.id
                  AND c1.date > c0.date
WHERE  c1.id IS NULL
ORDER  BY c0.id;

SQL Fiddle显示两者。