2014-04-16 30 views
6

Oracle sql'de iki tuple literalinin kesişimini elde etmek için bir işlev veya operatör veya başka bir basit (r) yapı var mı? n numaralar {n1, n2, n3, ..., n} bulmak id listesi göz önüne alındığında aşağıdaki tabloOracle SQL: Kesişen kümeleri için

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

sahip

: dikkate aşağıdaki örneği alarak

, öyle ki:

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 

iki olası çözümler şunlardır:

1. Çözüm 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. Çözüm 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) 
; 

Ancak aşağıdakileri yapmak için bir işlev/operatör var mı?

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

alternatif, daha basit yapı bu durum daha çok sayıda ve büyük olasılıkla daha karmaşık koşullar ile daha uzun sorgunun parçası olduğunu dikkate alarak, memnuniyetle karşılanacaktır.

Teşekkürler. Tek bir satırdan, oluşturabileceğiniz biraz regexp'in hile ile Ardından

değer başına bir satır ve masanıza karşı onları maç:

cevap

2

Benim fikrim with deyimi ile bir tabloya arama numaralarını dönüştürmek olduğunu in maddesi sayesinde:

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) 
; 

Bu beklenen verir:

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 
+0

'seçeneğini regexp_substr ('123, 456', '\ d +', 1, seviye) n çift den regexp_instr bağlanmak ('123, 456', '\ d +', 1, seviye)! = 0' çok faydalıdır. Bir masaya böldükten sonra olasılıklar çoktur. Fark ettiğim ilginç bir şey, sorgunun maliyetinin sabit kalması iken, 1 ve 2 numaralı çözümlerin maliyetleri aynıdır ve değişme eğilimindedir. – fluxy

1

kendi türünü ve işlevini oluşturarak Eğer bu tip beyan gerekir

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

Birinci:

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

Type created. 

... ve bu fonksiyon: İstediğiniz SQL çok benzer bir şey elde edebilirsiniz

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; 

Ancak olmak Her bir veri satırı için bir işlev çağrılarak ve dizinlerden yararlanmadan, bunun en performanslı çözüm olmayabileceğinin farkında olun!

+0

Bu ayrıca verileri tablolara ayırmanın harika bir yoludur. Ancak tercihim, @Emmanuel tarafından önerilen tekniğe gidiyor çünkü özel bir tür oluşturma ve daha iyi performans gösterme ihtiyacını ortadan kaldırıyor. – fluxy

+0

Evet, bu, @ Emmanuel'in çözümüyle gitmek için iki iyi neden. –