2013-01-24 75 views
9

我在PostgreSQL的是新的,并试图从SQL Server查询转换。Postgres的更新左连接

我有一个表用户,除其他外,列bUsrActive,bUsrAdmin和sUsrClientCode。我想更新的用户,并设置bUsrActive = false,如果不存在一个其他用户使用相同的sUsrClientCode其中bUsrAdmin =真实bUsrActive = TRUE。

在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 

我试图将其转换为Postgres的。我写了3种方法。

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)我理解为什么它不工作(它会更新所有用户)。我只是无法弄清楚如何在UPDATE ... SET部分引用table Users。

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)以下工作,但不使用连接。

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; 

我可能会用最后的解决方案。我只是想知道是否可以使用左连接来完成我想要的操作。

+1

出了什么问题,第三个? –

+1

没什么,它的工作。只是想知道如果我可以用另一种方式使用连接。看起来更好看!我想性能会是一样的。 – alfoks

+0

第二个应该工作(一见钟情)你得到的错误是什么?您是否意识到PostgreSQL中的FROM子句的语义与SQL Server相比有所不同? –

回答

12

下面是从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 
) 

ctid是一个伪列指向一个行的唯一位置。如果它有一个,你可以使用表的主键。

问题中的查询#2没有达到您的预期,因为更新后的表Users从未与FROM子句中的同一个表Users u连接。就像在FROM子句中放置两次表名一样,它们不会隐式地连接或绑定在一起,它们被视为两个独立的行集。

+0

感谢您的回答。看来我所要求的是无法完成的。我的意思是在查询#2的情况下,没有办法以某种方式引用u表。无论如何,我会记住你的解决方案,以备将来参考和更复杂的查询。现在,我将与第三个查询一起去。 – alfoks

1

我觉得这是做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; 
+0

我没有安装Postgres,并且距离我上次使用它已经2年了,但我相信您的查询在语法上不正确。否则,我的第一个查询也会起作用。如果我记得没错,在Postgres中你不能别名你正在更新的表。 – alfoks

+2

您可以别名正在更新的表。您不能在SET子句中使用该别名。 –

+0

这在语法上不正确。 –