2016-11-09 48 views
2

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那些在tbl1的外键IDa,其关系是一对多这样

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 SELECT我也想将数据从tbl2year 2015年将其复制并更改为2016年,但在

我已经试过这

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

但此查询GE因为一个字段在当时返回多个值。

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

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 | 
7 | 2016 | 4 | ddd | 
8 | 2016 | 4 | eee | 
9 | 2016 | 5 | fff | 
10 | 2016 | 6 | ggg | 
11 | 2016 | 6 | hhh | 
12 | 2016 | 6 | iii | 
--------------------------- 

这可能吗?

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

+0

你存储年份为人品? – jarlh

+0

使用tbl1中的临时列来存储原始主键。否则,您在复制数据时会丢失该信息。 –

+0

@jarlh不,其int int – JTR

回答

2

既然这样你的子查询不一行返回IDa,但所有的值全年。 (这是一个问题,因为你不能把所有这些值在一个字段一行。)

要解决您的确切语法,你需要“关联”对你是从读表的子查询,以便每行只能得到一个结果,以便您的IDa查找...

不幸的是,在您的情况下,这会变得非常混乱。你需要查看一下原来的IDa在表1,然后寻找在同一个表的匹配行,但明年...

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到pi在每种情况下。

剩下两个选择,因为我看到它:
- 从@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()ORDER BY子句中,以确保这两行在两年内都以相同的顺序出现。

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

+0

'tbl1.IDa'是更新的还是更旧的? – JTR

+1

@JTR - 对不起,打字错误,但我本来希望你意识到这是'新的',因为这是你要求的全部内容;)*(对不起,早期和特朗普的消息让我感到脾气和讽刺。)* – MatBailie

+0

这只适用于'tbl1(year,field2)'是唯一的。 –

0

我不完全了解您的数据 - 所以我不确定Field2和Field3每年的情况是否会一直相同。如果是这样,就可以:

INSERT INTO tbl2 (year, IDa, field3) 
SELECT c.Year, 
     c.Ida, 
     a.field3 
    FROM tbl2 a 
     INNER JOIN tbl1 b 
       ON a.IDa = b.Ida 
     INNER JOIN tbl1 c 
       ON field2 = field2 
       AND c.year = 2016 
WHERE a.year = '2015'; 
+0

yes,'field2'和'field3'每年的顺序相同 – JTR

+0

我已经试过了您的查询,但它没有返回任何内容:( – JTR

+0

@JTR将'ON field2 = field2'这一行更改为'ON c.field2 = b .field2' *(然后从'a','b'和'c'改变别名,使其更具可读性;))* – MatBailie

2

oIDa(原始ID)添加到tbl1

ALTER TABLE tbl1 ADD oIDa INT; 

与原身份证复印资料,所以你以后可以使用它。

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; 
+0

uumm ...我很抱歉,但是,什么是'INT UNSIGNED'又是什么? – JTR

+0

'INT UNSIGNED'意味着只有正整数(从0到4,294,967,295)。但是你可以采用与'IDa'相同的数据类型。 –

+0

对不起,刚刚实现了sql-server标签。我调整了代码。 –