用于字母数字检查的Oracle正则表达式

时间:2016-05-23 11:35:34

标签: oracle oracle11g

我们有下表结构。

From    To    Output
A001    A555  "A"
A556    A999  "B"
AA01    AA55  "C"
AA56    AA99  "D"
B001    B555  "C"

如果我的输入值大于From列且小于To列,则返回该输出。例如。如果我收到A222,则返回输出为“A”。如果我收到AA22,则返回输出为“C”。

目前我已经用Java处理了这个问题,但想检查一下我是否可以编写Oracle查询(使用Regex)来获得高于输出的结果。

由于 SACH

2 个答案:

答案 0 :(得分:1)

使用适当的(虚拟)列和索引创建表:

Oracle安装程序

CREATE TABLE table_name (
  "from"       VARCHAR2(10) UNIQUE,
  "to"         VARCHAR2(10) UNIQUE,
  output       CHAR(1)      NOT NULL,
  prefix       VARCHAR2(9)  GENERATED ALWAYS AS (
                              CAST(
                                REGEXP_SUBSTR( "from", '^\D+' )
                                AS VARCHAR2(9)
                              )
                            ) VIRTUAL,
  from_postfix NUMBER(9)    GENERATED ALWAYS AS (
                             TO_NUMBER( REGEXP_SUBSTR( "from", '\d+$' ) )
                            ) VIRTUAL,
  to_postfix   NUMBER(9)    GENERATED ALWAYS AS (
                              TO_NUMBER( REGEXP_SUBSTR( "to", '\d+$' ) )
                            ) VIRTUAL,
  CONSTRAINT table_name__from_to__u  PRIMARY KEY (
    prefix, from_postfix, to_postfix
  ),
  CONSTRAINT table_name__f_t_prefix__chk CHECK (
    REGEXP_SUBSTR( "from", '\^\D+' ) = REGEXP_SUBSTR( "to", '\^\D+' )
  )
);

INSERT INTO table_name ( "from", "to", output )
SELECT 'A001', 'A555', 'A' FROM DUAL UNION ALL
SELECT 'A556', 'A999', 'B' FROM DUAL UNION ALL
SELECT 'AA01', 'AA55', 'C' FROM DUAL UNION ALL
SELECT 'AA56', 'AA99', 'D' FROM DUAL UNION ALL
SELECT 'B001', 'B555', 'C' FROM DUAL;

COMMIT;

<强>查询

然后您的查询可以使用索引而不需要进行全表扫描:

SELECT output
FROM   table_name
WHERE  REGEXP_SUBSTR( :input, '^\D+' ) = prefix
AND    TO_NUMBER( REGEXP_SUBSTR( :input, '\d+$' ) )
         BETWEEN from_postfix
         AND     to_postfix;

<强>输出

如果input绑定变量为AA22,则结果为:

OUTPUT
------
C 

解释计划

PLAN_TABLE_OUTPUT
-------------------------------------------
Plan hash value: 2408507965
------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------ 
|   0 | SELECT STATEMENT            |                        |     1 |    35 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TABLE_NAME             |     1 |    35 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | TABLE_NAME__FROM_TO__U |     1 |       |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
--------------------------------------------------- 
       2 - access("PREFIX"= REGEXP_SUBSTR (:INPUT,'^\D+') AND "TO_POSTFIX">=TO_NUMBER(
              REGEXP_SUBSTR (:INPUT,'\d+$')) AND "FROM_POSTFIX"<=TO_NUMBER( REGEXP_SUBSTR (:INPUT,'\d+$')))
       filter("TO_POSTFIX">=TO_NUMBER( REGEXP_SUBSTR (:INPUT,'\d+$')))

答案 1 :(得分:0)

您必须从列和输入值中提取varchar和数值,并将它们相互比较

with tabl("FROM","TO",Output) as (
select 'A001','A555','A' from dual union all
select 'A556','A999','B' from dual union all
select 'AA01','AA55','C' from dual union all
select 'AA56','AA99','D' from dual union all
select 'B001','B555','C' from dual)
select * from tabl
where to_number(regexp_substr('AA22','[0-9]+')) between to_number(regexp_substr("FROM",'[0-9]+')) and to_number(regexp_substr("TO",'[0-9]+'))
and regexp_substr('AA22','[^0-9]+') = regexp_substr("FROM",'[^0-9]+')