用row_number()更新不起作用,为什么?

时间:2015-03-02 07:40:38

标签: sql postgresql sql-update common-table-expression postgresql-9.3

我有下表:

CREATE TABLE t_overview
(
  obj_uid uuid,
  obj_parent_uid uuid,
  obj_no integer,
  obj_text text,
  obj_path text,
  isdir integer,
  intid bigint,
  intparentid bigint
)

我想从uuid移至bigint并创建新列intidintparentid。我需要obj_uid的唯一整数(intid是主键),所以我只想用row_number() over (order by ...)进行更新。

似乎没有用。所以我试着将结果写入临时表,并通过join更新。但是我为每1获得了intid

但是当我从我更新的联接中选择时,我会得到1,2,3,4,5,6等等。我缺少什么?

DROP TABLE IF EXISTS mytable;
CREATE TEMP TABLE mytable AS
WITH CTE AS 
(
    SELECT obj_uid, obj_parent_uid, obj_no
        , obj_text, obj_path, isdir
        , intid as cteIntId
        , intparentid as cteParentId
        , row_number() over (order by obj_uid) as rn 
    FROM T_Overview 
)
SELECT * FROM CTE;

UPDATE T_Overview SET intid = mytable.rn 
FROM T_Overview AS bt 
INNER JOIN mytable 
    ON mytable.obj_uid = bt.obj_uid 


-- UPDATE T_Overview SET intid = CTE.rn FROM CTE;
-- UPDATE T_Overview SET intparentid = CTE.intid FROM CTE;

2 个答案:

答案 0 :(得分:2)

您的更新错误,T_Overview与(T_Overview + mytable)之间没有任何关系。

这个应该有效:

UPDATE T_Overview SET intid = mytable.rn 
FROM mytable 
WHERE mytable.obj_uid = T_Overview.obj_uid;

Offtopic:你的CTE没有多大意义,普通的SELECT会给你相同的结果。

答案 1 :(得分:2)

@Frank已经为您的错误提供了解释。

但你根本不需要临时表:

BEGIN;
LOCK T_Overview;  -- if there is concurrent write access

WITH cte AS (
   SELECT obj_uid, obj_parent_uid
        , row_number() OVER (ORDER BY obj_uid) AS intid
   FROM   T_Overview 
   )
UPDATE  T_Overview t
SET     intid       = upd.intid 
      , intparentid = upd.intparentid
FROM   (
   SELECT t1.*, t2.intid AS intparentid
   FROM   cte t1
   LEFT   JOIN cte t2 ON t2.obj_uid = t1.obj_parent_uid
   ) upd
WHERE t.obj_uid = upd.obj_uid;

COMMIT;

只有在可以进行并发写访问时才需要事务包装器和显式锁。 (对于临时表来说更是如此,你的中间有一个更大的时间段。)

假设参照完整性 - 从T_Overview.obj_parent_uidT_Overview.obj_uid的FK约束。 obj_parent_uid中的NULL值在intparentid中被转换为NULL。