如何使用子字符串结果对另一个表进行子串和连接

时间:2012-05-04 18:30:01

标签: sql oracle oracle10g

我有2个表:errorlookup和错误。 errorlookup有2列:代码和描述。 代码长度为2。 错误有2列id和错误代码。 错误代码的长度为40,这意味着它们为每个id编码存储20个错误代码。 我需要显示与id关联的所有描述,方法是将错误代码子串,并与errorlookup表中的代码匹配。 errorlookup的示例数据:

codes:description
   12:Invalid
   22:Inactive
   21:active

错误的示例数据:

id:errorcodes
 1:1221
 2:2112
 3:1222

我不能使用LIKE,因为它会导致太多错误。我希望将错误代码列分解为长度为2的字符串,然后与errorlookup连接。 怎么做到呢?

3 个答案:

答案 0 :(得分:2)

如果你真的无法改变表结构,这是另一种方法:

创建辅助numbers表:

CREATE TABLE numbers
( i INT NOT NULL 
, PRIMARY KEY (i)
) ;

INSERT INTO numbers VALUES
( 1 ) ;   
INSERT INTO numbers VALUES
( 2 ) ;
--- ...
INSERT INTO numbers VALUES
( 100 ) ;

然后你可以用这个:

SELECT err.id
     , err.errorcodes
     , num.i
     , look.codes
    , look.descriptionid
FROM
    ( SELECT i, 2*i-1 AS pos      --- odd numbers
      FROM numbers
      WHERE i <= 20               --- 20 pairs
    ) num 
  CROSS JOIN 
    errors  err
  JOIN 
    errorlookup  look
      ON look.codes = SUBSTR(err.errorcodes, pos, 2)
ORDER BY 
    err.errorcodes
  , num.i ;

SQL-Fiddle

进行测试
ID  ERRORCODES  I   CODES  DESCRIPTIONID
1   1221        1   12     Invalid
1   1221        2   21     Active
3   1222        1   12     Invalid
3   1222        2   22     Inactive
2   2112        1   21     Active
2   2112        2   12     Invalid

答案 1 :(得分:1)

我认为最干净的解决方案是使用PL / SQL函数“规范化”您的errocodes表。这样你就可以保持当前(破损)的表格设计,但仍然可以访问其内容,就像它被正确地规范化一样。

create type error_code_type as object (id integer, code varchar(2))
/

create or replace type error_table as table of error_code_type
/

create or replace function unnest_errors
   return error_table pipelined
is  
  codes_l integer;
  i       integer;
  one_row error_code_type := error_code_type(null, null);
begin
  for err_rec in (select id, errorcodes from errors) loop
    codes_l := length(err_rec.errorcodes);
    i := 1;
    while i < codes_l loop
        one_row.id   := err_rec.id;
        one_row.code := substr(err_rec.errorcodes, i, 2);
        pipe row (one_row);
        i := i + 2;
    end loop;
  end loop;
end;
/

现在使用此功能,您可以执行以下操作:

select er.id, er.code, el.description
from table(unnest_errors) er
  join errorlookup el on el.codes = er.code;

您还可以根据函数创建视图,使语句更容易阅读:

create or replace view normalized_errorcodes 
as
select *
from table(unnest_errors);

然后你可以简单地引用真实陈述中的视图。

(我在11.2上测试了这个,但我相信它也适用于10.x)

答案 2 :(得分:0)

我认为你与LIKE走在正确的轨道上。 MySQL有一个RLIKE函数,允许通过正则表达式进行匹配(我不知道它是否存在于Oracle中。)您可以使用errorlookup.code作为模式来匹配errors.errorcodes(..)*模式用于防止匹配“1213”之类的内容,例如“21”。

SELECT *
FROM error
JOIN errorlookup
WHERE errorcodes RLIKE CONCAT('^(..)*',code)
ORDER BY id;

+------+----------+------+
| id   | errorcode| code |
+------+----------+------+
|    1 | 11       | 11   |
|    2 | 1121     | 11   |
|    2 | 1121     | 21   |
|    3 | 21313245 | 21   |
|    3 | 21313245 | 31   |
|    3 | 21313245 | 32   |
|    4 | 21       | 21   |
+------+----------+------+