8

3 つの異なるファイル タイプを含むテーブルがあります。ファイル タイプ 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);

上記の基準に基づいて次のファイルを取得するための大きな厄介なクエリを作成したいと考えています。クエリが 4 回実行された場合、次の順序になります。

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

私を最も遠ざけた試みは、タイプごとに 3 つの個別のクエリを作成することでした。

--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 の場合は次の選択を使用しますが、すべて 1 つの SQL ステートメントで行います。

4

2 に答える 2

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;

更新された SQL Fiddleが再び機能していることを示しているため、評価された順序が要求したものであることがわかります。

いずれにせよ、これはテーブルに一度しかヒットしないため、利点になる可能性がありますが、全体をスキャンする必要があるため、そうではない可能性があります...

于 2013-09-30T20:25:36.470 に答える