我有这个问题:
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生成。)
答案 0 :(得分: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);
如果SELECT中没有重复项,您可能会考虑更快UNION ALL
而不是UNION
。否则,您需要UNION
来消除可能的欺骗行为。阅读here。
如果您的数据集很大,您可以考虑在 INSERT之后创建主键。那更快。
阅读IGNORE
的效果mySQL docs。
在重新访问该页面时,我意识到您在原始代码中提到了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_table
。 UNION
进入子选择,因此该子句只需要应用一次。应该是最快的
More on LEFT JOIN here