2015-03-31 59 views
4

我有一个问题,我试图将数据从一个表合并到另一个表中。在SQL中使用合并合并两个表

除了目标需要在第一列上有主键之外,源表和目标表是相同的。

的数据输入和预期的结果如下:

data in  Desired results 
c1 c2 c3  c1 c2 c3 
+--+--+--+ +--+------+------+ 
1 A x  1 A B C x y 
2 B z  2 B C z 
3 A z  3 A  z x y 
1 A y  +--+------+------+ 
3 A y 
1 B x  
2 C z  
1 C x  
3 A x 
1 A x 
+--+--+--+ 

我初始化表...

CREATE TABLE s (c1 char(2), c2 char(8), C3 char(8)) 

INSERT INTO s VALUES 
    ('1','A','x'), ('2','B','z'), ('3','A','z'), 
    ('1','A','y'), ('3','A','y'), ('1','B','x'), 
    ('2','C','z'), ('1','C','z'), ('3','A','x'), 
    ('1','A','x') 

CREATE TABLE d (c1 char(2) PRIMARY KEY, c2 char(8), C3 char(8)) 

我可以得到它使用游标工作...

DECLARE @c1 Char(2) 
DECLARE @c2 char(8) 
DECLARE @C3 char(8) 

DECLARE cur CURSOR FOR SELECT c1, c2, C3 FROM s 
OPEN cur 
FETCH NEXT FROM cur INTO @c1, @c2, @C3 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    UPDATE d SET 
    c2 = (CASE WHEN CHARINDEX(RTRIM(@c2), c2) > 0 THEN c2 ELSE SUBSTRING(RTRIM(c2) + ' ' + @c2, 1, 8) END), 
    c3 = (CASE WHEN CHARINDEX(RTRIM(@c3), c3) > 0 THEN c3 ELSE SUBSTRING(RTRIM(c3) + ' ' + @c3, 1, 8) END) 
    WHERE c1 = @c1 
    IF @@ROWCOUNT = 0 
    BEGIN 
    INSERT INTO d (c1, c2, c3) 
     VALUES (@c1, @c2, @c3) 
    END 
    FETCH NEXT FROM cur INTO @c1, @c2, @c3 
END 
CLOSE cur 
DEALLOCATE cur 

但我不能合并工作...
错误:Vi主键约束'PK__d__3213663B03BB8E22'的关联。无法在对象'dbo.d'中插入重复键。重复的键值是(1)。

MERGE INTO d USING s 
    ON (s.c1 = d.c1) 
    WHEN MATCHED THEN 
    UPDATE SET 
     c2 = (CASE WHEN CHARINDEX(RTRIM(s.c2), d.c2) > 0 THEN d.c2 ELSE SUBSTRING(RTRIM(d.c2) + ' ' + s.c2, 1, 8) END), 
     c3 = (CASE WHEN CHARINDEX(RTRIM(s.c3), d.c3) > 0 THEN d.c3 ELSE SUBSTRING(RTRIM(d.c3) + ' ' + s.c3, 1, 8) END) 
    WHEN NOT MATCHED THEN 
    INSERT (c1, c2, c3) VALUES (s.c1, s.c2, s.c3); 

有没有办法比再逐行多一点风度做到这一点?

感谢您的帮助!

+0

哪个RDBMS是这样的?请添加一个标签来指定您是使用'mysql','postgresql','sql-server','oracle'还是'db2' - 或者其他的东西。 – 2015-03-31 18:36:47

+0

@marc_s - 语法清楚地说它是'sql server' – 2015-03-31 18:44:53

回答

2

您可以避免RBAR操作使用For XML Path技巧来连接每个组的行。

;WITH cte1 
    AS (SELECT DISTINCT c1,cs.c2 AS c2 
     FROM s AS A 
       CROSS apply (SELECT DISTINCT c2 + ' ' 
          FROM s AS B 
          WHERE A.c1 = B.c1 
          FOR xml path('')) cs (c2)), 
    cte3 
    AS (SELECT DISTINCT c1,cs.c3 AS c3 
     FROM s AS A 
       CROSS apply (SELECT DISTINCT c3 + ' ' 
          FROM s AS B 
          WHERE A.c1 = B.c1 
          FOR xml path('')) cs (c3)) 
SELECT A.c1, 
     a.c2, 
     b.c3 
FROM cte1 A 
     INNER JOIN cte3 B 
       ON A.c1 = b.c1 
0

这是最好留给表示层,

可以使用corelated子查询来连接C2的值,C3基础上,集团由C1

您需要使用STUFF以及for xml path以获取连接字符串

select c1, stuff((select distinct ' ' + c2 
       from s 
       where s.c1 = outs.c1 
       for xml path('')), 1,1,''), 
      stuff((select distinct ' ' + c3 
       from s 
       where s.c1 = outs.c1 
       for xml path('')), 1,1,'') 
from s outs 
group by outs.c1