[英]Copy datasets with n:m-relation
我想使用單個SQL語句
insert into T (...) select ... from T where ...
復制很多數據集。 我的問題是從表T
到其他表有N:M關系,這些也必須被復制。 如果我不知道哪個原始數據集屬於哪個復制數據集,我該怎么做呢? 讓我舉例說明。
表T
:
ID | COL1 | COL2
-----------------
1 | A | B
2 | C | D
N:來自表T的M表引用表U(表U未顯示):
T | U
---------
1 | 100
1 | 101
2 | 100
2 | 102
我的復制操作[???]是我不知道的部分:
insert into T (COL1, COL2) select COL1, COL2 from T
insert into NM (T, U) select [???]
表T
:
ID | COL1 | COL2
-----------------
1 | A | B
2 | C | D
3 | A | B
4 | C | D
N:M-表:
T | U
---------
1 | 100
1 | 101
2 | 100
2 | 102
3 | 100
3 | 101
4 | 100
4 | 102
注意:
如果你足夠幸運地運行當前的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);
如果(col1, col2)
不是唯一的 ,我會看到另外兩種方式:
row_number()
使非唯一行唯一。 t.id
空間中INSERT
沒有孔的行,就像上面的查詢一樣。 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;
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;
有關手冊中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;
步驟1.鎖定(兩個)表或確保僅運行此腳本。 禁用FK檢查。
步驟2.按以下順序使用這兩個INSERT
語句:
INSERT INTO NM
(T, U)
SELECT
T + maxID, U
FROM
NM
CROSS JOIN
( SELECT MAX(ID) AS maxID
FROM T
) AS m
INSERT INTO T
(ID, COL1, COL2)
SELECT
ID+maxID, COL1, COL2
FROM
T
CROSS JOIN
( SELECT MAX(ID) AS maxID
FROM T
) AS m
步驟3.重新啟用FK。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.