Заменить переменные MySQL в PostgreSQL? - PullRequest
4 голосов
/ 07 января 2012

Мы часто используем быстрые одноразовые файлы SQL для вставки или обновления данных в существующей базе данных.SQL обычно пишется разработчиком, тестируется в системе разработки и затем импортируется в рабочую БД с psql -U dbuser dbname < file.sql.

. (Тривиальный) пример может выглядеть следующим образом:

INSERT INTO employees (
    company_id,
    name,
    position,
    created_by,
    last_modified_by
) VALUES
(
    (SELECT id FROM companies WHERE name = 'Acme Fellowship'),
    'Frodo Baggins',
    'Ring bearer',
    (SELECT id FROM users WHERE login = 'admin'),
    (SELECT id FROM users WHERE login = 'admin')
),
(
    (SELECT id FROM companies WHERE name = 'Acme Fellowship'),
    'Samwise Gamgee',
    'Rope bearer',
    (SELECT id FROM users WHERE login = 'admin'),
    (SELECT id FROM users WHERE login = 'admin')
),
(
    (SELECT id FROM companies WHERE name = 'Acme Fellowship'),
    'Peregrin Took',
    'Ent rider',
    (SELECT id FROM users WHERE login = 'admin'),
    (SELECT id FROM users WHERE login = 'admin')
);

Хотя это работает, в подзапросах много повторяющегося кода.Было бы неплохо (более эффективно и менее подвержено ошибкам) ​​хранить соответствующие значения для companies.id и users.id во временных переменных.В этом интерпретируемом примере разница в производительности, вероятно, минимальна, но на практике у нас действительно есть более сложные запросы и обновления, и часто имеется более трех обновленных / вставленных записей.

Тот же пример, написанный для MySQL, выглядит следующим образомthis:

SELECT @company_id := id FROM companies WHERE name = 'Acme Fellowship';
SELECT @admin_id := id FROM users WHERE login = 'admin';
INSERT INTO employees (
    company_id,
    name,
    position,
    created_by,
    last_modified_by
) VALUES
(@company_id, 'Frodo Baggins',  'Ring bearer', @admin_id, @admin_id),
(@company_id, 'Samwise Gamgee', 'Rope bearer', @admin_id, @admin_id),
(@company_id, 'Peregrin Took',  'Ent rider',   @admin_id, @admin_id);

Есть ли способ достичь чего-то похожего в PostgreSQL?

На что я смотрел:

  • переменные сессии psql (с помощью \set): нельзя использовать для хранения результатов запроса
  • plpgsql: можно использовать только в процедуре (мы все еще выполняем 8.4)
  • временных таблиц: я не вижу, как это сделатьиспользуйте их, не создавая уродливых и запутанных утверждений

Если нет прямого эквивалента для Postgres, что, по вашему мнению, было бы наименее неуклюжим способом создания файлов обновлений такого типа?

Ответы [ 3 ]

4 голосов
/ 07 января 2012

Используйте VALUES () в SELECT, который должен работать:

INSERT INTO employees (
    company_id,
    name,
    position,
    created_by,
    last_modified_by
)
SELECT
    (SELECT id FROM companies WHERE name = 'Acme Fellowship'),
    name,
    position,
    (SELECT id FROM users WHERE login = 'admin'),
    (SELECT id FROM users WHERE login = 'admin')
FROM
    (VALUES -- all your new content here
        ('Frodo Baggins',  'Ring bearer'), 
        ('Samwise Gamgee', 'Rope bearer'), 
        ('Peregrin Took',  'Ent rider')
    ) content(name, position); -- use some aliases to make it readable
2 голосов
/ 15 апреля 2014

Это старый вопрос, но я обнаружил, что использование операторов WITH сделало мою жизнь проще:)

WITH c AS (
    SELECT company_id,
    FROM companies
    WHERE name = 'Acme Fellowship'
), u AS (
    SELECT *
    FROM users
    WHERE login = 'admin'
), n AS (
    SELECT *
    FROM
        (VALUES -- all your new content here
            ('Frodo Baggins',  'Ring bearer'), 
            ('Samwise Gamgee', 'Rope bearer'), 
            ('Peregrin Took',  'Ent rider')
        ) content(name, position)
)
INSERT INTO employees (
    company_id,
    name,
    position,
    created_by,
    last_modified_by
)
SELECT c.company_id, n.name, n.position, u.id, u.id
FROM c, u, n
2 голосов
/ 08 января 2012

Попробуйте использовать CTE или подзапросы для запроса значений один раз и вставлять их много раз.
Таким образом, вы можете заменить переменные стиля MySQL на стандартный SQL .

INSERT INTO employees
      (company_id, name, position, created_by, last_modified_by)
SELECT c.id      , name, position, u.id      , u.id
FROM  (SELECT id FROM companies WHERE name = 'Acme Fellowship') c
     ,(SELECT id FROM users WHERE login = 'admin') u
     ,(VALUES
         ('Frodo Baggins',  'Ring bearer') 
        ,('Samwise Gamgee', 'Rope bearer')
        ,('Peregrin Took',  'Ent rider')
      ) v(name, position)

Предполагая, что companies.name и users.login фактически уникальны. Несколько попаданий будут умножать строки для вставки.
Прочтите о команде INSERT в руководстве .


Вот моя тестовая установка с временными таблицами на случай, если кто-то захочет быстро просмотреть:

CREATE TEMP TABLE companies (id int, name text);
INSERT INTO companies VALUES (17, 'Acme Fellowship');

CREATE TEMP TABLE users (id int, login text);
INSERT INTO users VALUES (9, 'admin');

CREATE TEMP TABLE employees (
 company_id int
,name text
,position text
,created_by int
,last_modified_by int);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...