Конвертировать MySQL запрос в PostgreSQL - PullRequest
0 голосов
/ 28 сентября 2011

У меня есть этот запрос:

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, но, похоже, все они содержат сложные процедуры. Должен ли я написать процедуру для этого? И если бы мне пришлось написать один, как бы это выглядело? Могу ли я просто эмулировать IGNORE, используя вместо этого некоторый код PHP? (SQL-запросы генерируются PHP.)

1 Ответ

6 голосов
/ 28 сентября 2011

Вы бы написали так в 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, чтобы устранить возможные ошибки. Читайте здесь .
Если ваш набор данных большой, вы можете рассмотреть возможность создания первичного ключа после ВСТАВКИ. Это быстрее

Прочитайте 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;

LEFT JOIN ... WHERE t.id IS NULL исключает любые id, которые могут уже присутствовать в tmp_table. UNION входит в подвыбор, так что предложение нужно применять только один раз. Должно быть быстрее всего.
Подробнее о левом присоединении здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...