SQL 来自左连接的 Postgres 更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14498143/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Postgres update from left join
提问by alfoks
I'm new in PostgreSQL and trying to convert a query from SQL Server.
我是 PostgreSQL 新手,正在尝试从 SQL Server 转换查询。
I have a table Users with, among others, the columns bUsrActive, bUsrAdmin and sUsrClientCode. I want to update Users and set bUsrActive = false if there does not exist a another user with the same sUsrClientCode where bUsrAdmin = true and bUsrActive = true.
我有一个表用户,其中包括 bUsrActive、bUsrAdmin 和 sUsrClientCode 列。如果不存在具有相同 sUsrClientCode 的另一个用户,其中 bUsrAdmin = true 和 bUsrActive = true,我想更新用户并设置 bUsrActive = false。
In SQL Server I have this query
在 SQL Server 我有这个查询
UPDATE u SET u.bUsrActive = 0
FROM Users u
LEFT JOIN Users u2 ON u.sUsrClientCode = u2.sUsrClientCode AND u2.bUsrAdmin = 1 AND u2.bUsrActive = 1
WHERE u.bUsrAdmin = 0 AND u.bUsrActive = 1 AND u2.nkUsr IS NULL
I'm trying to convert this to postgres. I wrote 3 approaches.
我正在尝试将其转换为 postgres。我写了3种方法。
1) My first attempt. Obviously not working.
1)我的第一次尝试。显然不工作。
UPDATE Users u
SET bUsrActive = false
FROM Users u2
WHERE u.sUsrClientCode = u2.sUsrClientCode AND u2.bUsrAdmin = true AND u2.bUsrActive = true
AND u.bUsrAdmin = false AND u.bUsrActive = true AND u2.nkUsr IS NULL;
2) I understand why it's not working (it updates all users). I just can't figure out how can I reference table Users u in the UPDATE ... SET part.
2)我明白为什么它不起作用(它更新所有用户)。我只是不知道如何在 UPDATE ... SET 部分引用表 Users u 。
UPDATE Users
SET bUsrActive = false
FROM Users u
LEFT JOIN Users u2 ON u.sUsrClientCode = u2.sUsrClientCode AND u2.bUsrAdmin = true AND u2.bUsrActive = true
WHERE u.bUsrAdmin = false AND u.bUsrActive = true AND u2.nkUsr IS NULL;
3) The following is working, but not using join.
3)以下有效,但不使用join。
UPDATE Users
SET bUsrActive = false
WHERE NOT EXISTS (
SELECT 1
FROM Users u
WHERE u.sUsrClientCode = Users.sUsrClientCode AND u.bUsrAdmin = true AND u.bUsrActive = true
) AND Users.bUsrAdmin = false AND Users.bUsrActive = true;
I'll probably go with the last solution. I just wanted to know if it's possible to do what I want using a left join.
我可能会采用最后一个解决方案。我只是想知道是否可以使用左连接来做我想做的事情。
回答by Daniel Vérité
Here's a generic way to transform this update query from SQL-server form to PostgreSQL:
这是将此更新查询从 SQL 服务器形式转换为 PostgreSQL 的通用方法:
UPDATE Users
SET bUsrActive = false
WHERE
ctid IN (
SELECT u.ctid FROM Users u
LEFT JOIN Users u2 ON u.sUsrClientCode = u2.sUsrClientCode AND u2.bUsrAdmin = 1 AND u2.bUsrActive = 1
WHERE u.bUsrAdmin = 0 AND u.bUsrActive = 1 AND u2.nkUsr IS NULL
)
ctidis a pseudo-column that points to the unique location of a row. You could use instead the primary key of the table if it had one.
ctid是一个伪列,指向行的唯一位置。如果有主键,您可以改用表的主键。
The query #2 from the question doesn't do what you expect because the updated table Users
is never joined to the same table Users u
in the FROM clause. Just as when you put a table name twice in a FROM clause, they don't get implicitly joined or bound together, they are considered as two independant sets of rows.
问题中的查询 #2 不符合您的预期,因为更新后的表Users
从未连接到Users u
FROM 子句中的同一个表。就像在 FROM 子句中两次放入表名一样,它们不会隐式连接或绑定在一起,它们被视为两个独立的行集。
回答by Clive Paterson
I think this is the correct way of doing 2) I belive it's more optimal/efficient than doing a sub select.
我认为这是正确的做法 2) 我相信它比做子选择更优化/更有效。
UPDATE Users uOrig
SET bUsrActive = false
FROM Users u
LEFT JOIN Users u2 ON u.sUsrClientCode = u2.sUsrClientCode AND u2.bUsrAdmin = 1 AND u2.bUsrActive = 1
WHERE u.bUsrAdmin = 0 AND u.bUsrActive = 1 AND u2.nkUsr IS NULL
and uOrig.sUsrClientCode = u.sUsrClientCode;