Oracle SQL:交叉元组文字

时间:2014-04-16 09:07:57

标签: sql oracle

是否有函数或运算符或其他简单(r)构造来获取oracle sql中两个元组文字的交集?

考虑以下例子:

有下表

------------------------------
TABLE sometable
------------------------------
id | telephone | mobile | fax
------------------------------
 1 | 123       | 456    | 789

给出n个数字的列表{n1,n2,n3,...,n} 找到id,这样:

   telephone = n1 or mobile = n1 or fax = n1
or telephone = n2 or mobile = n2 or fax = n2
or telephone = n3 or mobile = n3 or fax = n3
....
or telephone = n  or mobile = n  or fax = n 

两个合理的解决方案是:

1。解决方案1 ​​

SELECT id FROM sometable
WHERE
   n1 IN (telephone, mobile, fax)
OR n2 IN (telephone, mobile, fax)
OR n3 IN (telephone, mobile, fax)
....
OR n  IN (telephone, mobile, fax)
;

2。解决方案2

SELECT id FROM sometable
WHERE
   telephone IN (n1, n2, n3, ..., n)
OR mobile    IN (n1, n2, n3, ..., n)
OR fax       IN (n1, n2, n3, ..., n)
;

但是有一个函数/运算符可以执行以下操作吗?

SELECT id
FROM sometable
WHERE
 intersect_function
 (
    (telephone, mobile, fax),
    (n1, n2, n3, ..., n)
 )
 = TRUE
;

另一种更简单的结构将受到欢迎,考虑到这种情况是较长查询的一部分,具有更多且可能更复杂的条件。

感谢。

2 个答案:

答案 0 :(得分:2)

我的想法是通过with子句将搜索号转换为表格:

然后使用一点regexp技巧,您可以从单行创建每个值一行,并通过in子句将它们与您的表匹配:

create TABLE sometable
(
  id number, 
  telephone number, 
  mobile number, 
  fax number
);

insert into sometable values(1, 123, 456, 789);
insert into sometable values(2, 0, 0, 123);
insert into sometable values(3, 456, 0, 0);

with w(n) as
(
  select regexp_substr('123, 456', '\d+', 1, level) n
  from dual
  connect by regexp_instr('123, 456', '\d+', 1, level) != 0
)
select *
from sometable s, w
where w.n in (s.telephone, s.mobile, s.fax)
;

这符合预期:

ID  TELEPHONE  MOBILE   FAX  N
1   123        456      789  123
2   0          0        123  123
1   123        456      789  456
3   456        0        0    456

答案 1 :(得分:1)

通过创建自己的类型和函数,您可以实现与所需SQL非常相似的东西:

SELECT id
FROM sometable
WHERE
 intersect_function
 (
    num_tab(telephone, mobile, fax),
    num_tab(123, 456)
 ) > 0;

首先,您需要声明此类型:

SQL> create type num_tab is table of number;
  2  /

Type created.

...而且这个功能:

create or replace function intersect_function
  ( p_tab1 num_tab
  , p_tab2 num_tab
  ) return number
is
  l_intersect num_tab;
begin
  l_intersect := p_tab1 multiset intersect p_tab2;
  return l_intersect.count;
end;

但是,请注意,通过为每行数据调用函数并且无法使用索引,这可能不是最高性能的解决方案!