2011-09-28 82 views
0

我有這個疑問:轉換MySQL查詢到PostgreSQL的

DROP TABLE IF EXISTS tmp_table; 
CREATE TEMPORARY TABLE tmp_table(id int primary key) 
IGNORE (
    SELECT user2role.userid AS userid 
    FROM user2role 
    INNER JOIN users ON users.id=user2role.userid 
    INNER JOIN role ON role.roleid=user2role.roleid 
    WHERE role.parentrole like 'H1::H2::H3::H4::H5::%') 
UNION (
    SELECT groupid 
    FROM groups 
    WHERE groupid IN (2,3,4)); 

該查詢原文爲MySQL和替代DROP TABLE IF EXISTS它使用IF NOT EXISTS。我改變了那部分,但我不知道該怎麼辦IGNORE

首先,IGNORE在做什麼?

我試過尋找PostgreSQL等價物,但它們似乎都涉及複雜的過程。我必須爲此編寫一個程序嗎?如果我必須寫一個,它會是什麼樣子?我可以用一些PHP代碼來模擬IGNORE嗎? (SQL查詢是由PHP生成的。)

回答

6

你會這樣寫在postgres中。
IGNORE在這裏是不相關的,因爲表格剛被重新創建並保證爲空。並且UNION保證沒有插入重複的行。

DROP TABLE IF EXISTS tmp_table; 

CREATE TEMP TABLE tmp_table(id int4 primary key); 

INSERT INTO tmp_table 
SELECT user2role.userid::int4 AS id 
    FROM user2role 
    JOIN users ON users.id = user2role.userid 
    JOIN role ON role.roleid = user2role.roleid 
WHERE role.parentrole like 'H1::H2::H3::H4::H5::%' 
UNION 
SELECT groupid::int4 
    FROM groups 
WHERE groupid in (2,3,4); 

如果在選擇重複就不會發生,你可能會考慮更快UNION ALL而不是UNION。否則你需要UNION來消除可能的欺騙。閱讀here
如果你的數據集很大,你可以考慮在插入之後創建主鍵。這更快。

閱讀mySQL docs關於IGNORE的影響。


在重訪網頁時,我意識到你在原代碼中提到了IF NOT EXISTS。 你不這樣說,但只有當原始代碼創建表時,只有當它不存在時纔有意義,這在INSERT之前引入了非空的可能性。在這種情況下,IGNORE是相關的,並且需要PostgreSQL中的等效項。

因此,這裏是替代答案爲您的問題的解釋。

CREATE TEMP TABLE IF NOT EXISTS已經是implemented in PostgreSQL 9.1
對於舊版本,我最近在SO上發佈了solution

CREATE TEMP TABLE IF NOT EXISTS tmp_table(id int4 primary key); 

INSERT INTO tmp_table 
SELECT x.id 
    FROM (
    SELECT user2role.userid::int4 AS id 
     FROM user2role 
     JOIN users ON users.id = user2role.userid 
     JOIN role ON role.roleid = user2role.roleid 
    WHERE role.parentrole like 'H1::H2::H3::H4::H5::%' 
    UNION 
    SELECT groupid::int4 
     FROM groups 
    WHERE groupid in (2,3,4) 
     ) x 
    LEFT JOIN tmp_table t USING (id) 
WHERE t.id IS NULL; 

LEFT JOIN ... WHERE t.id IS NULL排除任何id可能已經存在於tmp_tableUNION進入子選擇,因此該子句只需要應用一次。應該是最快的。
More on LEFT JOIN here

+0

哦,所以下面忽略的東西只是插入到新的臨時表中?那麼爲什麼使用忽略而不是插入? – zermy

+0

我不得不猜測。它可能在mySQL中很有用,但在postgres中不需要(也不存在)。關鍵字'IGNORE'的副作用就像處理重複鍵錯誤一樣只是警告。但這不會發生在這裏,因爲每個定義的「UNION」消除了重複。 –

+0

非常感謝,2個簡單的問題,你爲什麼要將int更改爲int4,並將Inner JOIN更改爲JOIN(是因爲Join默認爲Inner,所以沒關係?)? – zermy