如何基于状态联接表记录?

时间:2018-12-03 14:33:53

标签: oracle oracle11g left-join oracle-sqldeveloper

我有一个表,该表必须根据状态连接到另一个表。这是表1数据的示例:

ROWID  STATE 
 34     TX
 56     NY
 67     WA
 89     TX

表1中的每一行都有状态值。表2每种状态都有两个记录。这是示例:

ROWID   STATE       NAME  
 19      TX     Chuck, Brown
 20      TX     Nick, Johnes 

如表2所示,德克萨斯州有两条记录。如果我使用Left Outer Join并尝试执行以下操作:

LEFT OUTER JOIN Table 2 TB2
   ON TB1.STATE = TB2.SATE

然后输出将是这样的:

34 TX Chuck, Brwon
34 TX Nick, Johnes
89 TX Chuck, Brwon
89 TX Nick, Johnes

每行都是重复的,因为表1中有两个针对得克萨斯州的记录。然后我在表2中有两个针对得克萨斯州的记录。我想看的是这样:

ROWID   STATE     NAME 1         NAME 2
 34      TX    Chuck, Brwon    Nick, Johnes

基本上,我想将两行合并为一个,然后加入表1。我最近开始从事这个项目,我们使用Oracle数据库。如果有人知道实现此目标的好方法,请告诉我。谢谢。

2 个答案:

答案 0 :(得分:1)

基于样本所需的输出,我将输出限制为表1中的第一个状态实例,并按ID对数据透视表名称进行了排序,尽管这恰好与给定示例数据的名称字段的alpha顺序匹配。 / p>

查看此SQL Fiddle

Oracle 11g R2架构设置

请注意,在Oracle ROWID中是保留名称,因此我将其更改为ID。

CREATE TABLE Table1
    ("ID" number, "STATE" varchar2(2))
;

INSERT ALL 
    INTO Table1 ("ID", "STATE")
         VALUES (34, 'TX')
    INTO Table1 ("ID", "STATE")
         VALUES (56, 'NY')
    INTO Table1 ("ID", "STATE")
         VALUES (67, 'WA')
    INTO Table1 ("ID", "STATE")
         VALUES (89, 'TX')
SELECT * FROM dual
;

CREATE TABLE Table2
    ("ID" number, "STATE" varchar2(2), "NAME" varchar2(12))
;

INSERT ALL 
    INTO Table2 ("ID", "STATE", "NAME")
         VALUES (19, 'TX', 'Chuck, Brown')
    INTO Table2 ("ID", "STATE", "NAME")
         VALUES (20, 'TX', 'Nick, Johnes')
SELECT * FROM dual
;

查询1

select t1.id
     , t2.state
     , t2.name
  from (select min(id) id, state from table1 group by state) t1
  join table2 t2
    on t1.state = t2.state

Results

| ID | STATE |         NAME |
|----|-------|--------------|
| 34 |    TX | Nick, Johnes |
| 34 |    TX | Chuck, Brown |

查询2

with t1(id, state) as (
  select min(id) id, state from table1 group by state
), t2 as (   
  select state
       , row_number() over (partition by state order by name) rn
       , name
    from table2
)
select t1.id
     , pvt.*
  from t1
  join t2 pivot (max(name) for rn in (1 name_1,2 name_2)) pvt
    on t1.state = pvt.state

Results

| ID | STATE |       NAME_1 |       NAME_2 |
|----|-------|--------------|--------------|
| 34 |    TX | Chuck, Brown | Nick, Johnes |

答案 1 :(得分:1)

在该问题下的一条评论中,您说您将接受一个单独的串联 NAME列,这是一个选择;我使用CTE创建表,因此您需要从第13行开始。

SQL> with
  2  t1 (rid, state) as
  3    (select 34, 'TX' from dual union all
  4     select 56, 'NY' from dual union all
  5     select 67, 'WA' from dual union all
  6     select 89, 'TX' from dual
  7    ),
  8  t2 (rid, state, name) as
  9    (select 19, 'TX', 'Chuck, Brown' from dual union all
 10     select 20, 'TX', 'Nick, Johnes' from dual
 11    ),
 12  -- start here
 13  it2 as
 14    (select state, listagg(name, ' & ') within group (order by null) name
 15     from t2
 16     group by state
 17    )
 18  select min(t1.rid) rid,
 19    t1.state,
 20    it2.name
 21  from t1 join it2 on t1.state = it2.state
 22  and t1.state = 'TX'
 23  group by t1.state, it2.name;

       RID ST NAME
---------- -- ------------------------------
        34 TX Chuck, Brown & Nick, Johnes

SQL>