2013-09-30 13 views
7

Üç farklı dosya türü içerebilen bir tablom var. A tipi dosya varsa, A'yı seçin, B tipi B varsa ve aynı client_id ile C tipi yok, B'yi seçin, C tipi seçin.
Seçili dosyayı kaldıran başka bir sihir daha sonra gerçekleşir masadan. Koşullu seçim sütun değerine bağlı olarak

Ben Oracle 10g SQL veritabanında Aşağıdaki tablo:

ID | TYPE | CLIENT_ID 
######################## 
file1 | A | 1 
file2 | B | 1 
file3 | C | 1 
file4 | B | 2 

ve evde, sqlfidde veya sql de birlikte takip etmek isteyenler için: Ben oluşturmak umuyorum

create table files (
    id varchar(8) primary key, 
    type varchar(4), 
    client_id number 
); 
insert into files values ('file1', 'A', 1); 
insert into files values ('file2', 'B', 1); 
insert into files values ('file3', 'C', 1); 
insert into files values ('file4', 'B', 2); 

Sorgu dört kez çalıştırıldığında aşağıdaki sırayla sonuçlanması gereken yukarıdaki ölçütleri temel alan bir sonraki dosyayı almak için büyük bir kötü sorgu:

#1: file1, A, 1 (grab any As first) 
#2: file4, B, 2 (grab any Bs who don't have any Cs with the same client_id) 
#3: file3, C, 1 (grab any Cs) 
#4: file2, B, 1 (same as run #2) 
Bana en uzak var

girişimi her tip için üç ayrı sorguları yazmak için oldu:

--file type 'A' selector 
select * from files where type = 'A' 
--file type 'B' selector 
select * from files where type = 'B' and client_id = (
    select client_id from files group by client_id having count(*) = 1 
); 
--file type 'C' selector 
select * from files where type = 'C' 

Ben satır sayısı her sonra geri kontrol etmek istiyorum ve onu 0 kullanımının önümüzdeki seçme, ama hepsi ise bir SQL deyiminde.

cevap

6

Sen, bazı iç içe analitiği kullanabilirsiniz: bu son sonuca göre nasıl oluştuğunu

select id, type, client_id 
from (
    select t.*, 
    case when type = 'a'then 1 
     when type = 'b' and c_count = 0 then 2 
     when type = 'c' then 3 
    end as rnk 
    from (
    select f.*, 
     sum(case when type = 'a' then 1 else 0 end) 
     over (partition by client_id) as a_count, 
     sum(case when type = 'b' then 1 else 0 end) 
     over (partition by client_id) as b_count, 
     sum(case when type = 'c' then 1 else 0 end) 
     over (partition by client_id) as c_count 
    from files f 
) t 
) 
order by rnk; 

SQL Fiddle

gösteren.

Ya da belki biraz daha iyi ve sadece bence tek bir kayıt çekerek bu sefer bir döngü içine uç hedeftir (?): Gördüğünüz böylece

select id, type, client_id 
from (
    select t.*, 
    dense_rank() over (
     order by case when type = 'a' then 1 
     when type = 'b' and c_count = 0 then 2 
     when type = 'c' then 3 
     end, client_id) as rnk 
    from (
    select f.*, 
     sum(case when type = 'c' then 1 else 0 end) 
     over (partition by client_id) as c_count 
    from files f 
) t 
) 
where rnk = 1; 

Updated SQL Fiddle gösteren, yeniden çalışmaya Değerlendirilen sipariş sizin için sordu. bir avantaj olabilir, ama düzenlemek için

+0

Teşekkür ... olmayabilir, amaç sadece bir satır döndürmektir şeyi taramak zorunda olabilir bu sadece bir defa masaya değdiği

iki şekilde de,. Tablo küçük kalacaktır, böylece tüm şeyi taramak bir sorun değildir. – cazzer

+0

Gelecekte bu başkalarına yardımcı olur - Oracle, tüm ustalıklarıyla normlara aykırı davranmaya ve 'aksi' yerine 'başka' yerine varsayılan kepçeye sahip olmaya karar verdi. – killjoy

1

Tüm bu mantık gerçekten siparişin düzenine göre tıkanmış olabilir. Bu, SQL fiddle örneğinizde çalışır (bunu sağladığınız için teşekkürler, bu cevap onsuz birlikte olmazdı). Hemen hemen bir açıklama * ile ilginç bir siparişle soruyorsunuz. Bu emri, (ikinci durumunuz, b'nin olmadığı yerde) ile yapmak için kendimize de bir katılma ihtiyacımız olacak. Bu biraz daha karmaşık muhtemelen gerekenden daha bakar olsa

select f.* 
from files f 
left join files a on a.client_id = f.client_id and f.type = 'b' and a.type = 'c' 
order by 
case when f.type = 'a' then 1 
    when f.type = 'b' and a.id is null then 2 
    when f.type = 'c' then 3 
    when f.type = 'b' and a.id is not null then 4 
else 5 end