简体   繁体   English

在PostgreSQL中替换MySQL的变量?

[英]Substitute for MySQL's variables in PostgreSQL?

We often use quick one-off SQL files to insert or update data in an existing database. 我们经常使用快速的一次性SQL文件来插入或更新现有数据库中的数据。 The SQL is usually written by a developer, tested on the development system, and then imported in the production DB with psql -U dbuser dbname < file.sql . SQL通常由开发人员编写,在开发系统上测试,然后使用psql -U dbuser dbname < file.sql导入生产数据库。

A (trivial) example might look like this: 一个(普通的)示例可能如下所示:

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')
);

While this works, there's a lot of repetitive code in the subqueries. 虽然这有效,但子查询中有很多重复的代码。 It would be nice (more efficient and less error prone) to store the relevant values for companies.id and users.id in temporary variables. 这将是很好(更高效且不易出错),为相关的值存储companies.idusers.id在临时变量。 In this construed example, the performance difference is likely minimal, but in practice we do have more complex queries and updates, and there are often more than three updated/inserted records. 在这个解释的示例中,性能差异可能很小,但实际上我们确实有更复杂的查询和更新,并且通常有三个以上的更新/插入记录。

The same example written for MySQL looks like this: 为MySQL编写的相同示例如下所示:

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);

Is there any way to achieve something similar in PostgreSQL? 有没有办法在PostgreSQL中实现类似的东西?

What I've looked at: 我看过的内容:

  • psql's session variables (with \\set ): cannot be used to store query results psql的会话变量(带\\set ):不能用于存储查询结果
  • plpgsql: can only be used in a procedure (we're still running 8.4) plpgsql:只能在一个过程中使用(我们仍在运行8.4)
  • temporary tables: I can't see how to use them without creating ugly and convoluted statements 临时表:我无法看到如何使用它们而不会创建丑陋和复杂的语句

If there is no direct equivalent for Postgres, what do you think would be the least clumsy way to produce update files of this kind? 如果Postgres没有直接的等价物,那么您认为生成此类更新文件的最不实用的方法是什么?

Use VALUES() in a SELECT, that should work: 在SELECT中使用VALUES(),它应该起作用:

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

This is an old question, but I found that using WITH statements made my life easier :) 这是一个老问题,但我发现使用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

Consider using CTEs or subqueries to query values once and inserted them many times. 考虑使用CTE或子查询一次查询值并多次插入它们。
This way, you can replace MySQL style variables with standard SQL . 这样,您可以使用标准SQL替换MySQL样式变量。

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)

Assuming that companies.name and users.login are, in fact, unique. 假设companies.nameusers.login实际上是唯一的。 Multiple hits would multiply the rows to be inserted. 多次命中会将要插入的行相乘。
Read about the INSERT command in the manual . 阅读手册中INSERT命令


Here is my test setup with temporary tables in case anyone wants to have a quick look: 这是我的临时表的测试设置,以防有人想快速查看:

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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM