当表具有不等的行计数时,在SQL中唯一地连接行

时间:2012-05-18 18:28:18

标签: sql oracle join

背景

我正在开发一个用于跟踪线路片段的大型数据库。目前,数据库(Oracle)围绕三个主要表格构建:

1)地图详细信息表。定义特定地图的所有顶级详细信息,例如县/区/城市。每个映射都由下表中使用的序列号唯一标识。

2)走廊长度表。基本上,如果乌鸦飞过,如果那条走廊在公共或私人土地上,那么电线的长度是多久。因此,这里定义的镜头只是从A到B的距离。

3)线长表。此表存储有关可在给定通道中运行的不同电线的信息。每个工作电压有一行。因此,走廊可以具有多个长度的导线,例如; 12KV,33KV和66KV。

(1)中总会有一个地图记录,但(2)和(3)中有任意数量的行,而(2)和(3)中的行数通常不匹配。

问题:

我正在搜索一个连接这三个表的方法,这样每个镜头只报告一次。这通过示例得到最好的说明。以下是一个示例记录集:

Map Details:
-------------------------------------------
| SERIAL_NO | CNTY | DIST | MAP_NO (Name) |
|-----------------------------------------|
|         1 |   33 |   88 | 123-4567-8    |
-------------------------------------------

Corridor Details:
------------------------------------
| SERIAL_NO | PROPRTY_CD | CORR_FT |
|----------------------------------|
|         1 |     PUBLIC |     100 |
|         1 |    PRIVATE |     200 |
------------------------------------

Wire Details
---------------------------------
| SERIAL_NO | OPER_KV | WIRE_FT |
|-------------------------------|
|         1 |      12 |     300 |
|         1 |      33 |     200 |
|         1 |      66 |     200 |
---------------------------------

我追求的最终输出将如下所示:

--------------------------------------------------------------------------------------
| SERIAL_NO | CNTY | DIST | MAP_NO (Name) | PROPRTY_CD | CORR_FT | OPER_KV | WIRE_FT |
|------------------------------------------------------------------------------------|
|         1 |   33 |   88 | 123-4567-8    |     PUBLIC |     100 |      12 |     300 |
|         1 |   33 |   88 | 123-4567-8    |    PRIVATE |     200 |      33 |     200 |
|         1 |   33 |   88 | 123-4567-8    |       NULL |    NULL |      66 |     200 |
--------------------------------------------------------------------------------------

注意: 电线和走廊的片段在大多数情况下都不匹配(有电线倍增器,为简洁起见,这里没有显示)。此外,走廊表中可能有更多行与线表(没有电线的走廊)或反之亦然(在其中运行多条线的走廊)。

我已经尝试了很多不同的方法解决这个问题,但我似乎无法获得我想要的输出。我尝试过的每次加入都会导致值与以下内容重复或类似:

BAD:
--------------------------------------------------------------------------------------
| SERIAL_NO | CNTY | DIST | MAP_NO (Name) | PROPRTY_CD | CORR_FT | OPER_KV | WIRE_FT |
|------------------------------------------------------------------------------------|
|         1 |   33 |   88 | 123-4567-8    |     PUBLIC |     100 |      12 |     300 |
|         1 |   33 |   88 | 123-4567-8    |     PUBLIC |     100 |      33 |     200 |
|         1 |   33 |   88 | 123-4567-8    |     PUBLIC |     100 |      66 |     200 |
|         1 |   33 |   88 | 123-4567-8    |    PRIVATE |     200 |      12 |     300 |
|         1 |   33 |   88 | 123-4567-8    |    PRIVATE |     200 |      33 |     200 |
|         1 |   33 |   88 | 123-4567-8    |    PRIVATE |     200 |      66 |     200 |
--------------------------------------------------------------------------------------

要点:

我对这个长期问题表示道歉,但解释我所追求的内容有点复杂。长话短说,我想并排列出两个子表中的所有行(没有特定的顺序),同时为两个表之间的行差异填充NULL。提前谢谢。

1 个答案:

答案 0 :(得分:2)

您设置方式中的任务可以通过以下方式强制强制

--pseudo-tables with sample data
with t_map  as (select 1 serial_no, 33 cnty,  88 dist, '12345678' map_no from dual),
 t_corr as (select 1 serial_no, 'PUBLIC' property_cd, 100 corr_ft from dual union all
            select 1, 'PRIVATE', 200 from dual),
 t_wire as (select 1 serial_no, 12 oper_kv, 300 wire_ft from dual union all 
            select 1, 33, 200 from dual union all
            select 1, 66, 200 from dual)
--query itself
select m.serial_no, m.cnty, m.dist, m.map_no, r.*
  from  t_map m join 
        (select nvl(c.serial_no, w.serial_no)  serial_no, c.property_cd, c.corr_ft, w.oper_kv, w.wire_Ft from (
                        (select t_corr.*, row_number() over(partition by serial_no order by serial_no) rn from t_corr) c 
              full join (select t_wire.*, row_number() over(partition by serial_no order by serial_no) rn from t_wire) w 
                     on c.serial_no = w.serial_no and (c.rn = w.rn)
                       )
        ) r on r.serial_no = m.serial_no;

但是,如果我是你,我会关注你的评论中提到的问题;)