使用同一个表中的值更新行

时间:2012-11-22 00:51:00

标签: sql postgresql sql-update self-join

我有一张这样的表:

+------+-------+
|ID    | value |
+------+-------+
| 1    | 150   |
| 2    |       |
| 3    |       |
| 4    |       |
| 5    | 530   |
| 6    | 950   |
| 7    | 651   |
+-------+------+

我想复制最后3个值,最后我的表格如下:

+------+-------+
|ID    | value |
+------+-------+
| 1    | 150   |
| 2    | 530   |
| 3    | 950   |
| 4    | 651   |
| 5    | 530   |
| 6    | 950   |
| 7    | 651   |
+-------+------+

有可能吗?

3 个答案:

答案 0 :(得分:7)

使用自我加入

UPDATE mytable m
SET    value = m0.value
FROM   mytable m0
WHERE  m.id = (m0.id - 3)   -- define offset
AND    m.id BETWEEN 2 AND 4 -- define range to be affected
AND    m.value IS NULL;     -- make sure only NULL values are updated

如果ID空间中存在间隙,请使用windows函数row_number()获取无间隙ID。我在CTE中这样做,因为我将重复使用表两次进行自我加入:

WITH x AS (
   SELECT *, row_number() OVER (ORDER BY ID) AS rn
   FROM   mytable
   )
UPDATE mytable m
SET    value = y.value
FROM   x
JOIN   x AS y ON x.rn = (y.rn - 4567)   -- JOIN CTE x AS y with an offset
WHERE  x.id = m.id                      -- JOIN CTE x to original
AND    m.id BETWEEN 1235 AND 3455
AND    m.value IS NULL;

data-modifying CTEs需要PostgreSQL 9.1或更高版本。

答案 1 :(得分:0)

对于像这样的临时更新,可能不会有比三个简单更新语句更好的方法:

UPDATE mytable SET value = 530 WHERE id = 2;
UPDATE mytable SET value = 950 WHERE id = 3;
UPDATE mytable SET value = 651 WHERE id = 4;

问题是,这是一个临时更新,仅适用于此确切数据,还是您要为该表中的所有可能数据实施的常规更新规则?如果是这样,那么我们需要更多细节。

答案 2 :(得分:0)

硬编码的3出现两次,会被您想要的许多行所取代。它假设最后3条记录实际上有值。它接受这些值并按顺序将它们应用于具有空值的记录集。

update a
  set value = x.value
  from (

        select nullRows.id, lastRows.value

          from ( select id, value
                       ,(row_number() over(order by id) - 1) % 3 + 1 AS key
                   from ( select id, value
                            from a
                            order by id desc
                            limit 3
                        ) x
                   order by 1

               ) AS lastRows

              ,( select id
                       ,(row_number() over(order by id) - 1) % 3 + 1 AS key
                   from a
                   where value is null
                   order by id

               ) AS nullRows

         where lastRows.key = nullRows.key

      ) x

where a.id = x.id