将MySQL查询转换为PostgreSQL

zer*_*rmy 0 mysql sql 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));
Run Code Online (Sandbox Code Playgroud)

此查询最初是用MySQL编写的,而不是使用DROP TABLE IF EXISTSIF NOT EXISTS.我改变了这一部分,但我不知道该怎么办IGNORE.

首先,正在IGNORE做什么?

我试图寻找PostgreSQL等价物,但它们似乎都涉及复杂的程序.我必须为此编写程序吗?如果我必须写一个,它会是什么样子?我可以IGNORE使用一些PHP代码来模拟吗?(SQL查询由PHP生成.)

Erw*_*ter 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);
Run Code Online (Sandbox Code Playgroud)

如果SELECT中没有重复项,您可能会考虑更快UNION ALL而不是UNION.否则你需要UNION消除可能的欺骗.阅读这里.
如果数据集很大,可以考虑在INSERT 之后创建主键.那更快.

阅读关于效果的mySQL文档IGNORE.


在重新访问页面时,我意识到你IF NOT EXISTS在原始代码中提到了.你没有这么说,但只有原始代码只有在它不存在的情况下创建表才有意义,这就引入了它在INSERT之前不为空的可能性.在这种情况下IGNORE是相关的,需要PostgreSQL中的等价物.

所以这里是对你的问题的解释的替代答案.

CREATE TEMP TABLE IF NOT EXISTS在PostgreSQL 9.1中实现.
对于旧版本,我最近在SO上发布了一个解决方案.

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;
Run Code Online (Sandbox Code Playgroud)

LEFT JOIN ... WHERE t.id IS NULL排除id可能已存在的任何内容tmp_table.UNION进入子选择,因此该子句只需要应用一次.应该是最快的.
更多关于LEFT JOIN的信息.