我们经常使用快速的一次性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编写的相同示例如下所示:
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中实现类似的东西?
我看过的内容:
\set
):不能用于存储查询结果如果Postgres没有直接的等价物,你认为制作此类更新文件的最不起眼的方法是什么?
答案 0 :(得分:4)
在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
答案 1 :(得分:2)
考虑使用CTEs或子查询来查询值一次并多次插入。
这样,您可以用标准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)
假设companies.name
和users.login
实际上是唯一的。多次命中会使要插入的行相乘
阅读INSERT command in the manual。
这是我的临时表测试设置,以防有人想快速查看:
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);
答案 2 :(得分:2)
这是一个老问题,但我发现使用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