2013-01-24 74 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

這在語法上不正確。 –