sql - 如何使用单个 SQL 命令插入数据和删除重复行
问题描述
如果表中存在任何重复条目,那么将数据插入表同时删除的最佳方法是什么。有一种方法可以将重复的数据标识符存储到临时表中,然后将其删除。但这不是一种有效的方法。任何更好的想法将不胜感激。
我的桌子
CREATE TABLE account(
user_id serial PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR (50) NOT NULL,
email VARCHAR(355) UNIQUE NOT NULL,
created_on TIMESTAMP NOT NULL,
last_login TIMESTAMP
);
解决方案
“立即”的答案是简单地运行 DELETE 语句,然后在单个事务中运行 INSERT 语句。
假设您想要避免重复的用户名,那么您可以执行以下操作:
begin transaction
delete from account
where username = 'arthur';
insert into account(username, password, email, created_on)
values ('arthur', '****', 'arthur@h2g2.com', current_timestamp);
commit;
您可以将其组合成一个语句,但这并没有太大的区别:
with new_values (username, password, email, created_on) as (
values values ('arthur', '****', 'arthur@h2g2.com', current_timestamp);
), deleted as (
delete from the_table
where username = (select username from new_values)
)
insert into account
select *
from new_values;
这里唯一的优点是您不需要重复两次值。
但是,如果account
被其他表引用(即外键“指向” the_table
),那么这将不起作用,因为如果该行仍然被引用,则 DELETE 将失败。
更好的解决方案是使用INSERT ON CONFLICT
并使用新数据更新现有行:
insert into account(username, password, email, created_on)
values ('arthur', '****', 'arthur@h2g2.com', current_timestamp)
on conflict (username)
do update
set password = excluded.password,
email = excluded.email;
但是,如果电子邮件已经存在,这仍然会引发错误,但不幸的是,on conflict do update
您只能指定一个唯一约束。
为了处理两个不同的唯一约束,事情变得有点复杂:
with new_values (username, password, email, created_on) as (
values
('arthur', '***', 'arthur@h2g2.com', current_timestamp)
), inserted as (
insert into account(username, password, email, created_on)
select * from new_values
on conflict do nothing
returning id
)
update account
set password = nv.password
from new_values nv
where (account.username = nv.username or account.email = nv.email)
and not exists (select * from inserted);
首先进行插入尝试。如果违反了任何唯一约束,则简单地忽略插入(on conflict do nothing
)。
只有在上一步没有插入任何行时,才会执行最后的 UPDATE 语句。这是通过and not exists (select * from inserted
.
由于用户名或电子邮件可能导致违反约束,因此更新对这两列使用 or 条件来更新现有行。如果你愿意,你也可以在那里更新更多的列。
推荐阅读
- python - 如何通过单击 GUI 上的按钮将图像获取到同一目录文件夹中的另一个 .py 文件中
- ruby-on-rails - 添加 gem 并得到这个错误 undefined method `acts_as_votable' for #
- postgresql - 如何在不使用命令行更改 postgresql 中的表结构的情况下格式化或更改列标题
- python - 如何将 ML 算法与词袋中的特征向量数据一起使用?
- docker - Docker/windowsfilter 占用大量磁盘空间
- php - password_verify,不明白为什么不起作用 | PHP, MYSQL
- android - 用画布绘制
- c# - 错误 CS0246:找不到类型或命名空间名称“PlayerMotor”
- npm-install - 为什么反应原生表单安装会出错?
- sql - 我可以在脚本编辑器 inSharepoint ( webpart) 中使用 SQL 吗?