use*_*167 3 mysql sql postgresql many-to-many insert
我想使用单个 SQL 语句
insert into T (...) select ... from T where ...
Run Code Online (Sandbox Code Playgroud)
复制大量数据集。我的问题是,从表到其他表存在 N:M 关系T,并且这些关系也必须复制。如果我不知道哪个原始数据集属于哪个复制数据集,我该怎么做?让我通过例子来演示一下。
桌子T:
ID | COL1 | COL2
-----------------
1 | A | B
2 | C | D
Run Code Online (Sandbox Code Playgroud)
N:M表从表T引用表U(表U未显示):
T | U
---------
1 | 100
1 | 101
2 | 100
2 | 102
Run Code Online (Sandbox Code Playgroud)
我的复制操作其中 [???] 是我不知道的部分:
insert into T (COL1, COL2) select COL1, COL2 from T
insert into NM (T, U) select [???]
Run Code Online (Sandbox Code Playgroud)
桌子T:
ID | COL1 | COL2
-----------------
1 | A | B
2 | C | D
3 | A | B
4 | C | D
Run Code Online (Sandbox Code Playgroud)
N:M-表:
T | U
---------
1 | 100
1 | 101
2 | 100
2 | 102
3 | 100
3 | 101
4 | 100
4 | 102
Run Code Online (Sandbox Code Playgroud)
注意:
如果您足够幸运能够运行当前的PostgreSQL 9.1,那么有一个优雅且快速的解决方案,只需使用新的数据修改 CTE 的单个命令即可。
MySQL就没有这样的运气了,它不支持公共表表达式(CTE),更不用说数据修改的 CTE。
假设(col1, col2)最初是唯一的:
t.id不会浪费任何序列号。WITH s AS (
SELECT id, col1, col2
FROM t
-- WHERE some condition
)
,i AS (
INSERT INTO t (col1, col2)
SELECT col1, col2 -- I gather from comments that id is a serial column
FROM s
RETURNING id, col1, col2
)
INSERT INTO tu (t, u)
SELECT i.id, tu.u
FROM tu
JOIN s ON tu.t = s.id
JOIN i USING (col1, col2);
Run Code Online (Sandbox Code Playgroud)
如果(col1, col2)不是unique,我看到另外两种方法:
row_number()使非唯一行变得唯一。INSERT空间中没有孔的行,t.id就像上面的查询一样。WITH s AS (
SELECT id, col1, col2
, row_number() OVER (PARTITION BY col1, col2) AS rn
FROM t
-- WHERE some condition
)
,i AS (
INSERT INTO t (col1, col2)
SELECT col1, col2
FROM s
RETURNING id, col1, col2
)
,r AS (
SELECT *
, row_number() OVER (PARTITION BY col1, col2) AS rn
FROM i
)
INSERT INTO tu (t, u)
SELECT r.id, tu.u
FROM r
JOIN s USING (col1, col2, rn) -- match exactly one id per row
JOIN tu ON tu.t = s.id;
Run Code Online (Sandbox Code Playgroud)
t.id,则相应的新行的序列号将被烧毁。t绘制默认值的新插入中收到重复的键错误。id我将此作为最后一步集成到命令中。这种方式最快、最安全。WITH s AS (
SELECT max(id) AS max_id
FROM t
)
,i AS (
INSERT INTO t (id, col1, col2)
SELECT id + s.max_id, col1, col2
FROM t, s
)
,j AS (
INSERT INTO tu (t, u)
SELECT tu.t + s.max_id, tu.u
FROM tu, s
)
SELECT setval('t_id_seq', s.max_id + s.max_id)
FROM s;
Run Code Online (Sandbox Code Playgroud)
手册中有关setval()的详细信息。
用于快速测试。
CREATE TEMP TABLE t (id serial primary key, col1 text, col2 text);
INSERT INTO t (col1, col2) VALUES
('A', 'B')
,('C', 'D');
CREATE TEMP TABLE tu (t int, u int);
INSERT INTO tu VALUES
(1, 100)
,(1, 101)
,(2, 100)
,(2, 102);
SELECT * FROM t;
SELECT * FROM tu;
Run Code Online (Sandbox Code Playgroud)
最近有一个有点类似的问题,我提供了有点类似的答案。加上版本8.3的替代方案,不带 CTE 和窗口函数。
| 归档时间: |
|
| 查看次数: |
878 次 |
| 最近记录: |