SQL将包含多个/重复值的表连接到表为1到1的两个字段

时间:2014-08-08 19:54:31

标签: sql oracle join

Oracle DB

Table1看起来如此,它是严格一对一的,没有重复......

Row   Primary   Secondary
--------------------------------
1     1     2
2     3     4
3     5     6

Table2具有相应的ID,每个ID都有多个名称。

ID      Name
------------------------
1       Server1
2       Server2
3       Server3
3       Server4
3       Server5
4       Server6
4       Server7
5       Server8
6       Server9
6       Server10

现在,这就是我现在正在做的事情,简化......

Select  t1.row row,
       t2.name p_name,
       t2a.name s_name
From table1 t1
left join table2 t2 on t1.primary = t2.id
left join table2 t2a on t1.secondary = t2a.id

这给了我这样的结果,我知道我使用的代码是正确的。

Row p_name      s_name
-------------------------------
1   Server1     Server2
2   Server3     Server6
2   Server3     Server7
2   Server4     Server6
2   Server4     Server7
2   Server5     Server6
2   Server5     Server7
3   Server8     Server9
3   Server8     Server10

我想要什么,无法弄清楚怎么做...得到这个结果:

Row   p_name    s_name
-------------------------------
1     Server1   Server2
2     Server3   Server6
2     Server4   Server7
2     Server5   null
3     Server8   Server9
3     null      Server10

本质上......我希望能够将值从1对1配对,其中每个值可以有1,2,3或更多,但我不想要所有组合,只是1,2或3,然后是另一组1,2或3,并且数字的空值不相等。我显然是SQL的新手并且已经四处寻找,我无法弄清楚下一步该尝试什么。

3 个答案:

答案 0 :(得分:2)

您需要另一个序列号的连接条件。幸运的是,您可以使用row_number()来获取此信息。这非常接近你想要的:

Select t1.row as row,
       t2.name as p_name,
       t2a.name as s_name
From table1 t1 left join
     (select t2.*, row_number() over (partition by t2.id order by t2.id) as seqnum
      from table2 t2
     ) t2
     on t1.primary = t2.id left join
     (select t2.*, row_number() over (partition by t2.id order by t2.id) as seqnum
      from table2 t2
     ) t2a
      on t1.secondary = t2a.id and t2.seqnum = t2a.seqnum;

不幸的是,它没有处理第二个列表比第一个列表长的情况。我认为这应该有效:

Select t1.row as row,
       t2.name as p_name,
       t2a.name as s_name
From table1 t1 left join
     (select t2.*, row_number() over (partition by t2.id order by t2.id) as seqnum
      from table2 t2
     ) t2
     on t1.primary = t2.id full outer join
     (select t2.*, row_number() over (partition by t2.id order by t2.id) as seqnum
      from table2 t2
     ) t2a
      on t1.secondary = t2a.id and t2.seqnum = t2a.seqnum;

答案 1 :(得分:1)

您可以使用rank()功能在重复的名称中创建“订单”,然后将其用作加入条件的一部分:

SELECT    t1.row, 
          primary_names.name AS p_name,
          secondary_names.name AS s_name
FROM      table1 t1
JOIN      (SELECT id, name, RANK() OVER (PARTITION BY name ORDER BY id ASC) AS rk
           FROM   table2) primary_names 
          ON t1.primary = primary_names.id
LEFT JOIN (SELECT id, name, RANK() OVER (PARTITION BY name ORDER BY id ASC) AS rk
           FROM   table2) secondary_names 
          ON t1.secondary = secondary_names.id AND 
             primary_names.rk = secondary_names.rk

答案 2 :(得分:0)

您可能拥有错误的数据模型。您正在尝试在Table1和Table2之间建立关系。

如果要在Table1上为此关系添加外键约束,则数据库不允许您,因为FK必须始终指向引用表上的主键。如果您尝试在ID列上的Table2上添加PK,则数据库也不允许您,因为此列上的值不是唯一的。

查看您的数据模型。之后,您的代码应如下所示:

        create table t2 (id number, name varchar2(10), 
        constraint t2PK primary key (id));

        create table t1 (nrow number, prim number, sec number, 
        constraint fkPrim foreign key (prim) references t2(id), 
        constraint fkSec foreign key (sec) references t2(id));

        insert into t2 values (1,       'Server1');
        insert into t2 values (2,       'Server2');
        insert into t2 values (3,       'Server3');
        insert into t2 values (4,       'Server7');
        insert into t2 values (5,       'Server8');
        insert into t2 values (6,       'Server9');

        insert into t1 values (1,     1,     2);
        insert into t1 values (2,     3,     4);
        insert into t1 values (3,     5,     6);
        commit;



        Select  t1.nrow nrow,
               t2a.name p_name,
               t2b.name s_name
        From  t1
        left join  t2 t2a on t1.prim = t2a.id
        left join  t2 t2b on t1.sec = t2b.id;

      NROW P_NAME     S_NAME    
---------- ---------- ----------
         1 Server1    Server2   
         2 Server3    Server7   
         3 Server8    Server9