2016-02-07 15 views
7

İki tablo arasında birleştirme nasıl yapılır, ancak birleştirme koşulunu karşılayan ilk satıra sınırlama nasıl yapılır?SQL: İlk bulunan satırdaki bir birleştirmeyi nasıl sınırlandırabilirsiniz?

Bu basit örnekte

, ben koşulu karşılar table_B dan table_A her satırın ilk satır için almak istiyorum:

select table_A.id, table_A.name, table_B.city 
from table_A join table_B 
on table_A.id = table_B.id2 
where .. 

table_A (id, name) 
1, John 
2, Marc 

table_B (id2, city) 
1, New York 
1, Toronto 
2, Boston 

The output would be: 
1, John, New York 
2, Marc, Boston 

Oracle (performans bir husustur) bu tür bir işlev sağlar olabilir. Sadece tek bir değeri istiyorsanız

+0

sel ect * from table_A birleşiminden (select * feom table_B grubunu id2'ye göre) b table_A.id = b.id2 burada .. –

+0

Satır numarası ile bir altkümeye katılın ve ekleme koşulu ekleyin ve row_number = 1 – Mihai

+0

Beklenen çıktının bir örneğini sağlama Belirli bir veriden (sahte tablo verileri) gereksiniminizi anlamamıza yardımcı oluruz. – saurav

cevap

1
select table_A.id, table_A.name, 
FIRST_VALUE(table_B.city) IGNORE NULLS 
     OVER (PARTITION BY table_B.id2 ORDER BY table_B.city) AS "city" 
from table_A join table_B 
on table_A.id = table_B.id2 
where .. 
3

bir skaler alt sorgu kullanılabilir:

SELECT 
    id, name, (SELECT city FROM table_B WHERE id2 = table_A.id AND ROWNUM = 1) city 
FROM 
    table_A 
0

Sorgu:

SELECT a.id, 
     a.name, 
     b.city 
FROM table_A a 
     INNER JOIN 
     (SELECT id2, 
       city 
     FROM (
      SELECT id2, 
        city, 
        ROW_NUMBER() OVER (PARTITION BY id2 ORDER BY NULL) rn 
      FROM Table_B 
     ) 
     WHERE rn = 1 
     ) b 
     ON (a.id = b.id2) 
--WHERE ... 

Çıkışlar:

 ID NAME CITY 
---------- ---- -------- 
     1 John New York 
     2 Marc Boston 
3

Buradaki anahtar kelime FIRST'dur. Analitik işlevini FIRST_VALUE veya toplu yapı FIRST kullanabilirsiniz. tanıtılan 12c yana

select table_A.id, table_A.name, firstFromB.city 
from table_A 
join (
    select table_B.id2, max(table_B.city) keep (dense_rank first order by table_B.city) city 
    from table_b 
    group by table_B.id2 
    ) firstFromB on firstFromB.id2 = table_A.id 
where 1=1 /* some conditions here */ 
; 

: Biz gereksiz pencere çeşit ve sonuç olarak daha düşük bir yürütme maliyeti yok çünkü FIRST veya LAST için
performans asla kötü ve dengi FIRST_VALUE veya LAST_VALUE yapı daha sık iyidir

select table_A.id, table_A.name, firstFromB.city 
from table_A 
cross apply (
    select max(table_B.city) keep (dense_rank first order by table_B.city) city 
    from table_b 
    where table_B.id2 = table_A.id 
    ) firstFromB 
where 1=1 /* some conditions here */ 
; 
1

: operatör LATERAL yanı sıra CROSS/OUTER APPLY mümkün JOIN maddesinin sağ tarafında bir korelasyon alt sorgu kullanmak yapmak birleşimler Oracle12c'de nihayet, herhangi bir geçici çözüm olmadan istediklerinizi sağlayacak yeni cross/outer apply operator var. Oracle 11g ve önceki sürümlerde

select * 
from (
     select USERNAME 
     from ALL_USERS 
     where USERNAME like 'SYS%' 
    ) U 
    cross apply (
     select OBJECT_NAME 
     from ALL_OBJECTS O 
     where O.OWNER = U.USERNAME 
      and ROWNUM = 1 
    ) 

:

aşağıdaki sadece için sözlük görünümlerde 'SYS' ile başlayan isimlerini sahip olanlar kullanıcılara ait (muhtemelen) birçok nesnelerden birini görünen bir örnektir Aynı sonuçları elde etmek için sadece ikinci tablonun ID'lerine dayanan ikinci tabloyu tarayan geçici çözümleri kullanmalısınız, ancak yavruları test etmek için lateral operator'u (yeni şeyleri etkinleştirmeksizin 12c'de de kullanılabilir) etkinleştirebilir ve bunu kullanabilirsiniz. bir

-- Enables some new features 
alter session set events '22829 trace name context forever'; 

select * 
from (
     select USERNAME 
     from ALL_USERS 
     where USERNAME like 'SYS%' 
    ) U, 
    lateral (
     select OBJECT_NAME 
     from ALL_OBJECTS O 
     where O.OWNER = U.USERNAME 
      and ROWNUM = 1 
    ); 
İlgili konular