在Oracle SQL中,如何使用多值列连接表

时间:2014-07-11 21:26:37

标签: sql oracle

我们的Oracle数据库中有一个遗留表,其中包含一个以逗号分隔值的列。这些以逗号分隔的值实际上是另一个表的外键。

Table: SCHEDULE
-----------------------
ID    NAME     DATES
--    ----     -----
1     Test1    10,20,30
2     Test2    20,40

Table: DATES
-----------------------
ID    DATE
--    ----
10    2013-01-01
20    2013-02-02
30    2013-03-03
40    2013-04-04

我正在尝试编写一个返回结果的查询:

ID   NAME   DATE
--   ----   ----
1    Test1  2013-01-01
1    Test1  2013-02-02
1    Test1  2013-03-03
2    Test2  2013-02-02
2    Test2  2013-04-04

我遇到了DBMS_UTILITY.comma_to_table程序,以及REGEXP_SUBSTR,SPLIT,JOIN等函数。但是我无法实现这一点。这里有什么帮助?

2 个答案:

答案 0 :(得分:5)

Yuch。但有时你必须处理这个问题。在Oracle中,您可以将like用于join条件:

select s.id, s.name, d.date
from schedule s join
     dates d
     on ',' || dates || ',' like '%,' || d.id || ',%';

效率不高,不能使用索引。但它应该可以解决你的问题。

请注意使用分隔符','。这可以防止10100匹配。

答案 1 :(得分:1)

长期来看,正确的解决方法是通过创建一个中间的多对多表来规范化数据。如果您仍需要维护遗留代码的DATES CSV列,您仍然可以使用触发器维护它。但这很容易,我不会在下面列出。这是一个简单的脚本,用于规范化数据并从现有数据生成关系表。

create table schedule_dates
(
 schedule_id int,
 date_id int,
 primary key(schedule_id, date_id)
);

填充链接表(多对多)

insert into schedule_dates
  select a.id, b.id from schedule a join dates b
                         on ','||a.dates||',' like '%,'||b.id||'%,';

创建一个视图以隐藏链接表:

create view V$SCHEDULE as
 select a.id, a.name, c.ts
    from schedule a
      join schedule_dates b on a.id = b.schedule_id
        join dates c on b.date_id = c.id
;

查询视图:

select * from V$SCHEDULE;

        ID NAME                 TS
---------- -------------------- ------------------
         1 Test1                12-APR-14
         1 Test1                12-MAY-14
         1 Test1                11-JUN-14
         2 Test2                12-MAY-14
         2 Test2                11-JUL-14