sql - 基于列值的条件选择

标签 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,则使用下一个选择,但都在一个 SQL 语句中。

最佳答案

您可以使用一些嵌套分析,尽管这看起来比它应该的要复杂一些:

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 ,再次显示正在工作,因此您可以看到评估的订单是您所要求的。

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

关于sql - 基于列值的条件选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19102645/

相关文章:

mysql - 每个键选择两行最近的时间

python - 如何在不确定数量的参数上使用 LIKE 和 % with pymssql?

sql - 组合行以创建两列数据

php - MySQL 查询按相对匹配顺序搜索关键字

oracle - Oracle 用户定义聚合函数的问题

sql - Oracle SQL "column ambiguously defined"和 `FETCH FIRST n ROWS ONLY`

mysql - 如何定义top-3评级?

java - MySQL 选择更新和插入

mysql - 连接多个表的 SQL 语法

mysql - 如何使用 MySQL 在两个日期之间进行查询?