【问题标题】:Efficient way of filtering data from column with mobile number separated by special characters. column has number with varchar2 datatype从带有特殊字符分隔的手机号码的列中过滤数据的有效方法。列具有 varchar2 数据类型的数字
【发布时间】:2018-02-06 10:07:08
【问题描述】:

我有一个表 customer,其中包含 cid、mobile_no 列。 cid 是独一无二的。 mobile_no 有多个手机号码,以逗号或反逗号分隔。该表包含超过 100k 条记录。现在,如果我得到一个电话号码作为一个客户的输入,并且在此基础上我需要获取 cid,然后将其与另一个表客户详细信息映射以获取值,我应该如何继续?我不能使用 like 运算符,因为对于超过 10 万条记录的表来说,它会很重。

例如:

ID mobile_no

cid_1 9263532727,"9738262783"....
cid_2 '8745362664,"'6384683633'";...

上面的例子可以被认为是手机号码的场景之一。 现在,如果我得到 6384683633 作为手机号码,在此基础上我需要获取 cid 并与其他表映射以获取客户的详细信息。

我可以将like 运算符与'%%' 一起使用,但这会使查询效率低下。

还有其他方法吗?

【问题讨论】:

  • 我猜任何方法都会因为糟糕的数据模型而效率低下。
  • 但是除了like操作符之外还有其他方法吗?
  • @DipanshuShekhar :可以想象的唯一可以拯救您的选择是重新设计您的表格。即使在表上添加索引也不会产生太大影响。作为like 的替代品,您可以使用INSTR()。但是,如果你这样做,我认为你不会看到查询性能有任何改进。
  • 尝试 regexp where mobile_no regexp('123456')
  • @Vishal,这是无效的,不是吗? Dipanshu,你最好重新设计模型——不会花太多时间,一个有两列的表,CID 和 MOBILE_NO。将当前值分成行是一次性的任务(当然,您需要修改前端应用程序才能将数据插入到新设计的表中),但后续操作应该会容易得多。跨度>

标签: sql oracle plsql oracle11g


【解决方案1】:

首先,是的 - 更改数据模型。

这是在看到@Dipanshu的评论后写的,要求另一种选择。

这种方法的想法是将手机号码分成几行(这就是 SPLIT_ME 所做的),然后简单地选择是否有任何与搜索字符串匹配的信息。

SQL> with test (id, mobile_no) as
  2    (select 1, '9263532727,9738262783' from dual union
  3     select 2, '8745362664,6384683633,9876543210' from dual
  4    ),
  5  split_me as
  6    (select id, regexp_substr(mobile_no, '[^,]+', 1, column_value) mobile_no
  7     from test,
  8          table(cast(multiset(select level from dual
  9                              connect by level <= regexp_count(mobile_no, ',') + 1
 10                             ) as sys.odcinumberlist))
 11    )
 12  select * From split_me
 13  where mobile_no = &search_mobile_no;
Enter value for search_mobile_no: 9876543210

        ID MOBILE_NO
---------- --------------------------------
         2 9876543210

SQL>

【讨论】:

  • 太棒了!非常感谢@littlefoot。
【解决方案2】:

建议 #1:

不要采用这种设计

建议 #2:

如果您必须采用这种设计,您可以使用文本索引来解析出索引值,例如

SQL> create table t (  cid int, mobs varchar2(1000));

Table created.

SQL>
SQL> insert into t
  2  select c, listagg(num,',') within group ( order by num )
  3  from
  4  ( select mod(rownum,1000) c, trunc(dbms_random.value(1000000,9999999)) num from dual connect by level <= 4000 )
  5  group by c;

1000 rows created.

SQL>
SQL> select * from t
  2  where rownum <= 10;

       CID MOBS
---------- --------------------------------------------------
       710 1309670,2250891,2446498,6381871
       711 6441062,7421544,8803290,8980956
       712 5216092,6664995,7971562,8615836
       713 2699908,4060187,7669498,8998292
       714 2565735,2621571,4071919,9443984
       715 1284533,2445570,6669291,8675917
       716 2368712,4074744,7804389,9798070
       717 1037619,4071820,4235448,7026192
       718 2955831,6282004,7131543,9027507
       719 4040856,4761599,4859829,9179022

10 rows selected.

SQL>
SQL> begin
  2        ctx_ddl.drop_preference('my_lexer');
  3        ctx_ddl.create_preference('my_lexer', 'BASIC_LEXER');
  4        ctx_ddl.set_attribute('my_lexer', 'numgroup', '~');
  5  end;
  6  /

PL/SQL procedure successfully completed.

SQL>
SQL> create index ix on t ( mobs ) indextype is ctxsys.context PARAMETERS('lexer my_lexer');

Index created.

SQL> set autotrace on
SQL> select * from t
  2  where contains(mobs,'7804389') > 0;

       CID MOBS
---------- --------------------------------------------------
       716 2368712,4074744,7804389,9798070

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1339481741

------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |     1 |   527 |     4   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T    |     1 |   527 |     4   (0)| 00:00:01 |
|*  2 |   DOMAIN INDEX              | IX   |       |       |     4   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("CTXSYS"."CONTAINS"("MOBS",'7804389')>0)

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)


Statistics
----------------------------------------------------------
        196  recursive calls
          0  db block gets
        152  consistent gets
          1  physical reads
          0  redo size
        640  bytes sent via SQL*Net to client
        608  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          6  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL>
SQL>

【讨论】:

    猜你喜欢
    • 2022-11-13
    • 2016-01-27
    • 1970-01-01
    • 1970-01-01
    • 2014-05-10
    • 2017-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多