2017-11-17 152 views
0

我想在Postgres上運行一些更新查詢,這些查詢是在公共字段上加入表的。這是用SQL Server運行的,更新計數是1,這是預期的,而postgres的更新計數是3.似乎postgres不執行隱式連接,當目標表與連接中涉及的源表名稱相同時。該腳本可以更DESCRIPT比在說什麼,那就是:Postgres加入不正確的更新

drop table test; 
drop table test2; 
create table test(col1 int, col2 varchar(10)); 
insert into test values(1, 'aaa'); 
insert into test values(2, 'bbb'); 
insert into test values(3, 'ccc'); 
create table test2(col1 int); 
insert into test2 values(2); 
select * from test; 
select * from test2; 

// Select join = rowcount 1 
select count(*) from test t2, test2 t3 
where t2.col1 = t3.col1; 

// SQL Server update = 1; postgres =3 
update test set col2 = 'changed' 
from test t2, test2 t3 
where t2.col1 = t3.col1; 

上面的查詢可以簡化爲:

update test set col2 = 'changed' 
from test2 where test.col1 = test2.col1; 

但是這不是我的本意爲加盟條款可能涉及一些更多的聯合聲明。 期望意圖是運行這樣的查詢:

UPDATE IDMAP_CHILD_JOBID SET RESTORESUCCESS = IDMAP_TABLE_JOBID.RESTORESUCCESS, RESTOREERRMSG = IDMAP_TABLE_JOBID.RESTOREERRMSG 
FROM CHILD, IDMAP_TABLE_JOBID 
WHERE CHILD.ID = IDMAP_CHILD_JOBID.OLDID AND CHILD.FK1 = IDMAP_TABLE_JOBID.OLDID 
AND IDMAP_TABLE_JOBID.RESTORESUCCESS = $FALSE 

Postgres的與表抱怨指定多次如果IDMAP_CHILD_JOBID相同IDMAP_TABLE_JOBID更多。這怎麼可以重寫? 我的應用程序應該生成一個更新語句,這是統一的查詢應該運行,而行爲是不同的。顯然,加入是在選擇時執行的,而不是正在更新。

+1

[從手動報價](https://www.postgresql.org/docs/current/static/sql-update.html):「*注意,目標表必須** **未出現在from_list ,除非你打算自我加入*「。你需要從'FROM'部分 –

+0

刪除''IDMAP_TABLE_JOBID'一些聯接statements'有沒有這樣的事,作爲一個* JOIN語句*。 JOIN是一個二元**運算符**,它的操作數是兩個表(表達式),其結果是一個表表達式。 – wildplasser

+0

@wildplasser我離題了。 SQL Server更新可以運行JOIN。可能不會使用術語,但可以通過SELECT with JOINS獲得相似性。 – dmachop

回答

1

如果您需要引用同一個表兩次(或更多),你需要給他們不同的別名,讓您可以參考他們每個人:


update test t1 
set col2 = 'changed' 
from test t2 --  <<-- same table !! 
JOIN test2 t3 ON t2.col1 = t3.col1; 
where t1.something =t3.something  --<<-- link the target to the source 
     ; 

UPDATE idmap_child_jobid dst -- <<-- alias=dst 
SET restoresuccess = src.restoresuccess 
, restoreerrmsg = i.restoreerrmsg 
FROM idmap_table_jobid src -- <<-- same table, different alias=src 
JOIN child c ON c.fk1 = src.oldid 
WHERE c.id = dst.oldid 
AND dst.restoresuccess = false 
     ; 

[未經檢驗的,因爲我不知道該表的定義,或者INTEN查詢系統蒸發散]


This is run with SQL Server

SQL服務器有一個稍微不同的語法(和語義)更新,在:

UPDATE test 
SET field= 'OMG' 
FROM test t1 
JOIN othertable t2 ON t1.field = t2.field 
    ; 

...有只有兩張表在範圍表中;即使test被提到了兩次,這是相同的實體)這是微軟/的Sybase 功能

+0

反芻剛纔你所說的一切: 的Postgres 更新測試d 集COL2 =從測試T1「改爲」 ,test2的T 2,其中t1.col1 = t2.col1和d .something = t2.something; SQL服務器 更新d 組d.col2 = '改爲' 從測試d,測試T1,T2 TEST2其中t1.col1 = t2.col1和d.something = t2.something; – dmachop

+0

我正在寫不得不產生這樣的SQL語句的方法和這一標準少UPDATE語句加入似乎是一場噩夢 !例如: 字符串updateOnJoin(字符串destTable,集<一對<字符串,字符串>> setPairs,收藏個fromTables,收集<配對<字符串,字符串>> joinStatements) 每呼叫者不得不產生別名和構建這似乎是一個難於編碼方式的方法:( – dmachop

0

對於這個SQL查詢:

update test 
    set col2 = 'changed' 
    from test t2, test2 t3 
    where t2.col1 = t3.col1; 

等效Postgres的語法是:

update test 
    set col2 = 'changed' 
    from test2 t3 
    where test.col1 = t3.col1; 

update/join語法是在兩個數據庫不同(雖然我覺得上面還將努力在SQL Server)。

+0

這不是我的意圖。這是我想要做的簡化。在我的問題UPDATE IDMAP_CHILD_JOBID SET RESTORESUCCESS = IDMAP_TABLE_JOBID.RESTORESUCCESS,RESTOREERRMSG = IDMAP_TABLE_JOBID.RESTOREERRMSG 從子,IDMAP_TABLE_JOBID WHERE CHILD.ID = IDMAP_CHILD_JOBID.OLDID AND CHILD.FK1 = IDMAP_TABLE_JOBID.OLDID AND IDMAP_TABLE_JOBID.RESTORESUCCESS = $ FALSE最終查詢是我的本意,但似乎沒有要在SQL服務器和Postgres使用方式時IDMAP_TABLE_JOBID相同IDMAP_CHILD_JOBID。這個度假勝地別名具有兩種不同的語法:( – dmachop

0

我有點困惑,似乎有 3 tables: IDMAP_CHILD_JOBID, CHILD, IDMAP_TABLE_JOBID

簡體查詢(SQry) 2 tables: test,test2和 最終查詢(FQry)之間的差異要更新SQry單列:(注意,T1別名希望防止table specified more than once錯誤)

update test t1 
    set col2 = 'changed' 
    from test t2, test2 t3 
where t2.col1 = t3.col1 
    and t1.col1 = t3.col1; 

所以FQry將更新行從該查詢返回的,如果有在IDMAP_CHILD_JOBID多行匹配CHILD.ID其中,他們都將得到更新。

select IDMAP_CHILD_JOBID.RESTORESUCCESS, 
     IDMAP_TABLE_JOBID.RESTORESUCCESS, RESTOREERRMSG, 
     IDMAP_TABLE_JOBID.RESTOREERRMSG 
FROM IDMAP_CHILD_JOBID, CHILD, IDMAP_TABLE_JOBID 
WHERE CHILD.ID = IDMAP_CHILD_JOBID.OLDID 
    AND CHILD.FK1 = IDMAP_TABLE_JOBID.OLDID 
    AND IDMAP_TABLE_JOBID.RESTORESUCCESS = $FALSE