根据列值进行条件选择

时间:2013-09-30 19:54:45

标签: sql oracle select oracle10g

我有一个表可能包含三种不同的文件类型。如果存在文件类型A,则选择A,否则如果存在文件类型B并且没有具有相同client_id的类型C,则选择B,否则选择类型C.
稍后会发生一些其他魔法,从表中删除所选文件。

我在Oracle 10g SQL数据库中有以下表格:

 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,则使用下一个select,但是在一个SQL语句中。

2 个答案:

答案 0 :(得分:7)

您可以使用一些嵌套分析,但这看起来比它可能应该更复杂:

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,再次展示工作,这样您就可以看到评估的订单是您要求的。

无论哪种方式,这只能击中一次,这可能是一个优势,但必须扫描整个事情,这可能不是......

答案 1 :(得分: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