2013-09-30 9 views
7

У меня есть таблица, которая может содержать три разных типа файлов. Если присутствует тип файла A, выберите A, иначе, если присутствует тип файла B И нет типа Cs с тем же идентификатором client_id, выберите B, иначе выберите тип C.
Некоторая другая магия произойдет позже, которая удалит выбранный файл из таблицы.Условный выбор на основе значения столбца

У меня есть следующая таблица в 10g SQL базы данных Oracle:

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

и для тех, кто хочет следовать вдоль дома, sqlfidde или 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); 

Я надеюсь создать большой неприятный запрос для захвата следующего файла на основе вышеуказанных критериев, что должно привести к следующему порядку, если запрос был запущен четыре раза:

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

Попытка, что у меня дальше всего было написать три отдельных запросов для каждого типа:

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

Я хочу, чтобы проверить количество строк, возвращаемых после каждого, и если это 0 использовать следующий выбор, но все в одном выражении SQL.

ответ

6

Вы можете использовать несколько вложенных аналитику, хотя это выглядит немного более сложным, чем это, вероятно, следует:

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 показывая, как это строит до конечного результата.

Или, может быть немного лучше, и на этот раз только потянув один рекорд, который я думаю, что это конечная цель внутри цикла (?):

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, показывая снова работает, так что вы можете увидеть оцененный порядок - это то, о чем вы просили.

В любом случае это только попадает в таблицу один раз, что может быть преимуществом, но должен сканировать всю вещь, которая не может ...

+0

Спасибо за редактирование, цель состоит в том, чтобы вернуть только одну строку. Стол останется маленьким, поэтому сканирование всего не является проблемой. – cazzer

+0

Просто так это помогает кому-то еще в будущем - Oracle, во всей своей изобретательности решил пойти против нормы и иметь по умолчанию bucket как «else» вместо «в противном случае», – killjoy

1

Вся эта логика может быть переполнена в порядке с помощью заявления. Это работает в вашем экземпляре скрипта SQL (спасибо за то, что этот ответ не объединился бы без него). Вы в значительной степени просите выбор * с интересным заявлением по порядку. Чтобы выполнить этот порядок (ваше второе условие, b, где c не существует), нам также понадобится самоподключение.

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 
Смежные вопросы