2013-09-30 28 views
7

Mam tabelę, która może zawierać trzy różne typy plików. Jeśli plik typu A jest obecny, wybierz opcję A, w przeciwnym razie, jeśli plik typu B jest obecny I nie ma typu C z tym samym identyfikatorem klienta, wybierz opcję B, w przeciwnym razie wybierz typ C.
Kolejna magia nastąpi później, co spowoduje usunięcie wybranego pliku ze stołu.Wybór warunkowy oparty na wartości kolumny

Mam poniższej tabeli w bazie danych 10g Oracle SQL:

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

i dla tych, którzy chcą podążać w domu, sqlfidde lub SQL:

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

Mam nadzieję stworzyć duże nieprzyjemne zapytanie, aby pobrać następny plik w oparciu o powyższe kryteria, co powinno doprowadzić do następującej kolejności, jeśli zapytanie zostało uruchomione cztery razy:

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

Próba że dostał mi najdalej było napisanie trzech oddzielnych zapytań dla każdego typu:

--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' 

Chcę sprawdzić liczbę wierszy zwracanych po każdym i jeśli jest 0 użycie następnego select, ale wszystko w jednym poleceniu SQL.

Odpowiedz

6

Można użyć kilka zagnieżdżonych Analytics, choć wygląda to nieco bardziej skomplikowane niż to prawdopodobnie powinien:

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 pokazując, w jaki sposób buduje się na wynik końcowy.

A może nieco lepiej, a tym razem tylko ciągnąc jeden rekord, który moim zdaniem jest cel końcowy wewnątrz pętli (?):

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, pokazujący pracę ponownie, więc można zobaczyć oceniona kolejność jest tym, o co prosiłeś.

Tak czy inaczej to tylko uderza w stół raz, co może być zaletą, ale musi zeskanować całą rzecz, która nie może ...

+0

Dzięki za edycji, celem jest, aby powrócić tylko jeden wiersz. Stół pozostanie mały, więc skanowanie całej sprawy nie jest problemem. – cazzer

+0

Po to, aby pomóc komuś innemu w przyszłości - Oracle, w całej ich pomysłowości, zdecydowało się pójść wbrew normie i mieć domyślną wartość "else" zamiast "inaczej" – killjoy

1

Cała ta logika może zostać wepchnięta do porządku przez polecenie naprawdę. Działa to w twojej instancji fiddle SQL (dzięki za zapewnienie, że ta odpowiedź nie byłaby połączona bez niej). Prosisz o wybór * z interesującym rozkazem według instrukcji. Aby wykonać tę kolejność przez (twój drugi warunek, b, gdzie c nie istnieje) będziemy potrzebować samołączenia.

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