微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

mysql – 使用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

注意:

>我有数以千计的数据集(不只是两个)
>我想使用’insert … select’来获得更好的性能

解决方法:

如果你足够幸运地运行当前的Postgresql 9.1,那么使用新的data-modifying CTEs只需一个命令即可获得优雅而快速解决方案.

没有这样的运气,MysqL不支持Common Table Expressions (CTE),更不用说数据修改CTE了.

假设(col1,col2)最初是唯一的:

查询1

>在这种情况下,您可以轻松地从表中选择任意切片.
>不会浪费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)不是唯一的,我会看到另外两种方式:

查询2

>使用window function row_number()使非唯一行唯一.
>在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;

查询3

>这是基于@ypercube已经提供的相同的想法,但是在一个查询中.
>如果当前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;

有点similar question recently,我提供了一个类似的答案.对于没有CTE和窗口功能的8.3版本的替代品.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐