试图从两个具有一对多关系的表中选择插入

时间:2016-11-09 08:38:08

标签: sql sql-server

我有tbl1

IDa | year | field2 |
----+------+---------
1   | 2015 | bbb    |
2   | 2015 | aaa    |
3   | 2015 | ccc    |
---------------------

我正在使用INSERT INTO SELECT复制2015年的所有数据,但将year更改为2016

INSERT INTO tbl1 (year, field2) SELECT '2016', field2 from tbl1 WHERE year = '2015'

并返回这样的数据

IDa | year | field2 |
----+------+---------
1   | 2015 | bbb    |
2   | 2015 | aaa    |
3   | 2015 | ccc    |
4   | 2016 | bbb    |
5   | 2016 | aaa    |
6   | 2016 | ccc    |
---------------------

现在,我有另一个表tbl2在[{1}}中有IDa的外键,其关系是这样的一对多

tbl1

现在,使用IDb | year | IDa | field3 | ----+------+-----+--------- 1 | 2015 | 1 | ddd | 2 | 2015 | 1 | eee | 3 | 2015 | 2 | fff | 4 | 2015 | 3 | ggg | 5 | 2015 | 3 | hhh | 6 | 2015 | 3 | iii | --------------------------- ,我还要复制INSERT INTO SELECTtbl2的数据并将其更改为2016,但year中的IDa 2016

我试过这个

year

但是这个查询收到错误,因为当时一个字段返回多个值。

那么,如何为此做出正确的查询?我希望结果是这样的

INSERT INTO tbl2 (year, IDa, field3)
    SELECT year, (SELECT IDa FROM tbl1 WHERE year = '2016'), field3
    FROM tbl2
    WHERE year = '2015'

有可能吗?

我很感谢所有答案,谢谢你的帮助。

3 个答案:

答案 0 :(得分:2)

就目前而言,您的子查询不会返回一行的IDa,而是返回全年的所有值。 (这是一个问题,因为您无法将所有这些值放在一行中的一个字段中。)

要修复您的确切语法,您需要将子查询与您正在阅读的表“关联”,以便每行只获得一个结果,以便进行IDa查找...

不幸的是,在你的情况下,这会非常混乱。您需要在table1中查找原始IDa的内容,然后在同一个表中查找匹配的行但是明年...

INSERT INTO
    tbl2 (
        year,
        IDa,
        field3
    )
SELECT
    year + 1,
    (SELECT IDa
       FROM tbl1
      WHERE year   = tbl2.year + 1
        AND field2 = (SELECT field2
                        FROM tbl1
                       WHERE IDa = tbl2.IDa
                     )
    ),
    field3
FROM
    tbl2
WHERE
    year = '2015'

也就是说,有一种更简单的方法,使用连接...

INSERT INTO
    tbl2 (
        year,
        IDa,
        field3
    )
SELECT
    newer.year,
    newer.IDa,
    tbl2.field3
FROM
    tbl2
INNER JOIN
    tbl1   older
       ON  older.IDa    = tbl2.IDa
INNER JOIN
    tbl1   newer
       ON  newer.year   = older.year + 1
       AND newer.field2 = older.field2
WHERE
    tbl2.year = 2015

<强> 修改

如果field2不存在,您就会遇到在每种情况下都不知道选择IDa的问题。

我认为有两种选择:
- 使用@PaulSpiegel的方法 - 手动引入代理

就个人而言,这听起来越来越复杂,基本的重新设计听起来似乎是有益的。

如果您无法重新设计或使用@PaulSpiegel中的方法,则可以选择...

INSERT INTO
    tbl2 (
        year,
        IDa,
        field3
    )
WITH
   ordered_tbl1
(
    SELECT
        ROW_NUMBER() OVER (PARTITION BY year ORDER BY year)   AS ordinal,
        tbl1.*
    FROM
        tbl1
)
SELECT
    newer.year,
    newer.IDa,
    tbl2.field3
FROM
    tbl2
INNER JOIN
    ordered_tbl1    older
       ON  older.IDa     = tbl2.IDa
INNER JOIN
    ordered_tbl1    newer
       ON  newer.year    = older.year + 1
       AND newer.ordinal = older.ordinal
WHERE
    tbl2.year = 2015

这假定tbl1中的唯一字段为yearIDa。如果您在tbl1中有其他字段,那么它们应该包含在ROW_NUMBER()的{​​{1}}子句中,以确保这两行中的行显示的顺序相同。

如果这对您没有意义,那么您可能不应该使用它。而是重新设计或使用@PaulSpiegel的方法。

答案 1 :(得分:2)

将列oIDa(原始ID)添加到tbl1

ALTER TABLE tbl1 ADD oIDa INT;

使用原始ID复制数据,以便日后使用。

INSERT INTO tbl1 (year, field2, oIDa) SELECT '2016', field2, IDa from tbl1 WHERE year = '2015';

现在您有一个可以加入的列,以查找新生成的IDa值:

INSERT INTO tbl2 (year, IDa, field3)
    SELECT year, tbl1.IDa, tbl2.field3
    FROM tbl2
    JOIN tbl1 ON tbl1.oIDa = tbl2.IDa
    WHERE tbl2.year = 2015;

现在您可以删除新列:

ALTER TABLE tbl1 DROP COLUMN oIDa; 

答案 2 :(得分:0)

我并不是100%了解您的数据 - 所以我不确定Field2和Field3每年是否总是相同。如果是,那么这应该有效:

<span ng-bind="data"></span>