我需要更新数据库中的表。为简单起见,我们假设表的名称为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
约束会很麻烦。
答案 0 :(得分:2)
答案 1 :(得分:1)
你不应该使用非描述性的列名id
,即使有些半机智的ORM习惯这样做。我使用tab_id
代替此演示。
我以这种方式解释您的描述:您有其他表格,其中FK列指向到 tab.col
。与我下面示例中的表child1
一样。
要清理混乱,请在单个会话中执行所有 以保留我使用的临时表。更好的是,在单笔交易中完成所有工作。
更新所有引用表格,让所有引用行指向"首先" (明确地说! - 如何定义)在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?
现在,所有引用都指向"第一个"在一组愚蠢的人中,你已经获得了杀死其他人的许可。
删除重复的行,但tab
中的第一行除外。
DELETE FROM tab t
USING up
WHERE t.col = up.old_col
确保所有引用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?
通过删除空格
来清理您的值UPDATE tab
SET col = replace(col, ' ', '');
这只会处理好的旧空格字符(ASCII值32,Unicode U + 0020)。你有别人吗?
所有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]*', '');