where in list问题

  
  
  1. where in list问题
  2. 1.使用正则
  3. var v_emp varchar2(200);
  4. exec :v_emp := 'CLARK,MILLER,KING';
  5. select * from emp
  6. where ename in
  7. (
  8.  SELECT regexp_substr(:v_emps, '[^,]+', 1, LEVEL) AS ename
  9.    FROM dual
  10.  CONNECT BY LEVEL <= (length(translate(:v_emps, ',' || :v_emps, ',')) + 1)
  11. );
  12. 2.使用context
  13. DBMS_SESSION.SET_CONTEXT (
  14.   namespace VARCHAR2,
  15.   attribute VARCHAR2,
  16.   value     VARCHAR2,
  17.   username  VARCHAR2,
  18.   client_id VARCHAR2 );
  19. --这个上下文的名字是inlist_ctx,需要由过程set_inlist_ctx_prc创建
  20. create or replace context inlist_ctx using set_inlist_ctx_prc;
  21. create or replace procedure set_inlist_ctx_prc(p_val in varchar2)
  22.  /**
  23.  ||程序说明:
  24.  ||上下文inlist_ctx属性名为str
  25.  ||p_val为属性对应的值
  26.  **/
  27. as
  28. begin
  29.  dbms_session.set_context('inlist_ctx','str',p_val);
  30. end;
  31. /
  32. 创建动态视图,让sys_context动态给视图传参数
  33. create or replace view v_inlist
  34.  as
  35.  select substr(inlist,
  36.    instr(inlist,',',1,level)+1,
  37.    instr(inlist,',',1,level+1) - instr(inlist,',',1,level)-1) as value_str
  38.  from (select ','||sys_context('inlist_ctx','str')||',' as inlist from dual)
  39.  connect by level<=length(sys_context('inlist_ctx','str')) - length(replace(sys_context('inlist_ctx','str'),','))+1;
  40. 测试
  41. exec set_inlist_ctx_prc('ab,bc,cd');
  42. select value_str from v_inlist;
  43. VALUE_STR
  44. --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  45. ab
  46. bc
  47. cd
  48. 修改上下文的属性值,则试图也改变
  49. exec set_inlist_ctx_prc('papapa,hahah,keke');
  50. select value_str from v_inlist;
  51. VALUE_STR
  52. --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  53. papapa
  54. hahah
  55. keke
  56. 通过测试发现,动态试图正常工作,而且因为保存在context内的树形是在session范围内的,具有很好地并发性。
  57. exec set_inlist_ctx_prc;
  58. select * from emp
  59. where ename in (
  60.  select value_str from v_inlist);
  61. 写到过程里就是先接收传入的参数,然后执行set_inlist_ctx_prc,最后执行查询
  62. 3.使用集合构造伪表
  63. 一个函数用来解析字符串并返回一个集合,然后用table()函数
  64.       
          
    1. 注意不能是index by表,必须是schema级别的类型,数组有容量也不常使用

  65. create or replace type varchar2_tt as table of varchar2(1000);
  66.  /
  67. create or replace function f_str2list(in_str in varchar2,
  68.                           in_delimiter in varchar2 default ',')
  69.  return varchar2_tt
  70. /**
  71. ||程序说明:将按指定分隔符分隔的字符串转为嵌套表类型变量返回
  72. ||输入变量:
  73. ||        in_str 字符串,如'a,b,c'
  74. ||        in_delimiter 分隔符,默认是逗号
  75. ||输出变量:
  76. ||        varchar2_tt类型,嵌套表
  77. **/
  78.  as
  79.      v_str     varchar2(32767) default in_str||in_delimiter;
  80.      v_result  varchar2_tt := varchar2_tt();
  81.      i number;
  82. begin
  83.  loop
  84.      exit when v_str is null;
  85.      i := instr(v_str,in_delimiter);
  86.      v_result.extend;
  87.      v_result(v_result.count) := trim(substr(v_str,1,i-1));
  88.      v_str := substr(v_str,i+1);
  89.  end loop;
  90.  return v_result;
  91. end;
  92. /
  93. var str varchar2(100);
  94. exec :str := 'XY,YZ';
  95. select count(*) from emp where ename in (
  96.  select column_value from table(cast(f_str2list(:str) as varchar2_tt))
  97.  );
  98. 一般来说in列表返回行数都比较少,一般来说应该走NL
  99. 要注意的是,用table()函数CBO会认为rows8168(其实这个默认的table函数基数是8168依赖于块大小,我这里是8K的块)
  100. Execution Plan
  101. ----------------------------------------------------------
  102. Plan hash value: 2659767359
  103. --------------------------------------------------------------------------------------------------
  104. | Id  | Operation                           | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
  105. --------------------------------------------------------------------------------------------------
  106. |   0 | SELECT STATEMENT                    |            |     1 |     8 |    33   (4)| 00:00:01 |
  107. |   1 |  SORT AGGREGATE                     |            |     1 |     8 |            |          |
  108. |*  2 |   HASH JOIN SEMI                    |            |     1 |     8 |    33   (4)| 00:00:01 |
  109. |   3 |    TABLE ACCESS FULL                | EMP        |    14 |    84 |     3   (0)| 00:00:01 |
  110. |   4 |    COLLECTION ITERATOR PICKLER FETCH| F_STR2LIST |  8168 | 16336 |    29   (0)| 00:00:01 |
  111. --------------------------------------------------------------------------------------------------
  112. Predicate Information (identified by operation id):
  113. ---------------------------------------------------
  114.   2 - access("ENAME"=VALUE(KOKBF$))
  115. 通过hint固定执行计划
  116. select count(*) from emp where ename in (
  117.  select /*+ cardinality(tab,5) */column_value from table(cast(f_str2list(:str) as varchar2_tt) a)
  118.  );
多行in list
  
  
  1. WITH TEMP AS
  2. (
  3.  SELECT 1 INT_ID,'ni' NAME,'12,13,14,a,b,~' REGION_ID FROM DUAL
  4.  UNION
  5.  SELECT 2 INT_ID,'wo' NAME,'13,14,F' REGION_ID FROM DUAL
  6.  UNION
  7.  SELECT 3 INT_ID,'ta' NAME,'11' REGION_ID FROM DUAL
  8. )
  9. SELECT T1.INT_ID,T1.NAME,REGEXP_SUBSTR(T1.REGION_ID,'[0-9a-zA-Z~]+',1,T2.LEV) REGION_ID FROM
  10. (SELECT TEMP.*,LENGTH(REGION_ID)-LENGTH(REPLACE(REGION_ID,',',''))+1 RN FROM TEMP) T1,
  11. (SELECT LEVEL LEV FROM DUAL
  12. CONNECT BY LEVEL <= (SELECT SUM(LENGTH(REGION_ID)-LENGTH(REPLACE(REGION_ID,',',''))+1) RN FROM TEMP)) T2
  13. WHERE T2.LEV <= T1.RN ORDER BY INT_ID,LEV
  14. select department_id,regexp_substr(first_name,'[^,]+',1,t2.lev) first_name from
  15. (select x.*,LENGTH(first_name)-LENGTH(REPLACE(first_name,',',''))+1 RN FROM x) t1,
  16. (select level lev from dual connect by level <=(SELECT SUM(LENGTH(first_name)-LENGTH(REPLACE(first_name,',',''))+1) RN FROM x)) T2
  17. where t2.lev <= t1.rn


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值