PostgreSQL更新查询

时间:2013-07-18 15:09:30

标签: sql postgresql

我需要更新数据库中的表。为简单起见,我们假设表的名称为tab,它有2列:id (PRIMARY KEY, NOT NULL)col (UNIQUE VARCHAR(300))。我需要以这种方式更新表:

id                    col
----------------------------------------------------
1                     'One two three'
2                     'One twothree'
3                     'One two       three'
4                     'Remove white spaces'
5                     'Something'
6                     'Remove whitespaces '

到:

id                    col
----------------------------------------------------
1                     'Onetwothree'
2                     'Removewhitespaces'
3                     'Something'

Id更新后的行数和顺序并不重要,可能会有所不同。我使用PostgreSQL。有些列是FOREIGN KEYs。这就是为什么从UNIQUE删除col约束会很麻烦。

3 个答案:

答案 0 :(得分:2)

我认为只使用这种格式的replace就能做到你想要的。

update tab
set col = replace(col, ' ', '');

这是一个SQLFiddle

答案 1 :(得分:1)

你不应该使用非描述性的列名id,即使有些半机智的ORM习惯这样做。我使用tab_id代替此演示。

我以这种方式解释您的描述:您有其他表格,其中FK列指向 tab.col。与我下面示例中的表child1一样。

要清理混乱,请在单个会话中执行所有 以保留我使用的临时表。更好的是,在单笔交易中完成所有工作。

  1. 更新所有引用表格,让所有引用行指向"首先" (明确地说! - 如何定义)在tab中的一组重复项中。

    创建一个用于所有更新的翻译表up

    CREATE TEMP TABLE up AS
    WITH t AS (
        SELECT tab_id, col, replace(col, ' ', '') AS col1
             ,row_number() OVER (PARTITION BY replace(col, ' ', '')
                                 ORDER BY  tab_id) AS rn
        FROM   tab
        )
    SELECT b.col AS old_col, a.col AS new_col
    FROM  (SELECT * FROM t WHERE rn = 1) a
    JOIN  (SELECT * FROM t WHERE rn > 1) b USING (col1);
    

    然后更新所有引用表。

    UPDATE child1 c
    SET    col = up.new_col
    FROM   up
    WHERE  c.col = up.old_col;
    
    --  more tables?   
    

    -> SQLfiddle

    现在,所有引用都指向"第一个"在一组愚蠢的人中,你已经获得了杀死其他人的许可。

  2. 删除重复的行,但tab中的第一行除外。

    DELETE FROM tab t
    USING  up
    WHERE  t.col = up.old_col
    
  3. 确保所有引用FK约束都具有 ON UPDATE CASCADE 子句。

    ALTER TABLE child1 DROP CONSTRAINT child1_col_fkey;
    
    ALTER TABLE child1  ADD CONSTRAINT child1_col_fkey FOREIGN KEY (col)
    REFERENCES tab (col)
    ON UPDATE CASCADE;
    
    -- more tables?
    
  4. 通过删除空格

    来清理您的值
    UPDATE tab
    SET    col = replace(col, ' ', '');
    

    这只会处理好的旧空格字符(ASCII值32,Unicode U + 0020)。你有别人吗?

  5. 所有FK约束都应指向tab.tab_id开头。您的表格会更小更快,所有这些都会更容易。

答案 2 :(得分:0)

我解决它比 Erwin 更容易。我的计算机上没有SQL来测试它,但这样的东西对我有用:

DELETE FROM tab WHERE id IN (
    SELECT id FROM (
        SELECT id, col, row_number() OVER (PARTITION BY regexp_replace(col, '[ \t\n]*', '')) AS c WHERE c > 1;
    )
)

UPDATE tab SET col = regexp_replace(col, '[ \t\n]*', '');