SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

分析関数の衝撃

分析関数の衝撃5(総集編)

CodeZineに掲載されたSQLを分析関数で記述する 5


  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード ソースコード (3.0 KB)

3. minus allとintersect allを模倣

 次は、minus allintersect allを模倣するSQLです。

 完結編の「2つのテーブルが相等かを判定するクエリ」では、下記のselect文で、重複行を許さない集合(空集合を考慮せず)の一致を調べました。

結果が0件なら「等しい」、1件以上なら「異なる」
select count(*) over(),a.* from tbl_A a
 minus
select count(*) over(),b.* from tbl_B b

 しかし、下記のように重複行を許す場合は、等しい集合でなくても結果が0件となってしまいます。

select count(*) over(),a.*
  from (select 1 as ColA from dual union all
        select 1 from dual union all
        select 2 from dual union all
        select 2 from dual union all
        select 3 from dual) a
 minus
select count(*) over(),b.*
  from (select 1 as ColA from dual union all
        select 2 from dual union all
        select 2 from dual union all
        select 3 from dual union all
        select 3 from dual) b;

 重複行を許す集合に対応するには、minusではなくminus allを使わなければいけないのです。しかし、Oracle11gの段階でminus allは実装されていません。そこで、minus allを模倣するSQLと、intersect allを模倣するSQLを考えてみます。

3-1 minus allを模倣

 まずは、minus allを模倣するSQLです。テーブルのデータと、出力結果を考えます。

tbl_A
ColA
1
1
2
2
3
tbl_B
ColA
1
2
2
3
3

 下記のminus allを模倣します。

select ColA from tbl_A
minus all
select ColA from tbl_B;
出力結果
ColA
1

 minus allを実装する上でのポイントは、重複する要素があったときに要素の数を考慮する点です。要素の数を考慮することに注目すると、答えは下記となります。

minus allを模倣
select ColA
from (select ColA,Row_Number() over(partition by ColA order by 1) from tbl_A
      minus
      select ColA,Row_Number() over(partition by ColA order by 1) from tbl_B);

 Row_Number関数で各要素に連番をつけてからminusを使い、minus allと同じ結果を取得しています。Row_Number関数には、こういった使い方もあるのです。

 SQLのイメージは下記となります。赤線がpartition byのイメージで、緑線がminusによる出力しない制御のイメージです。

SQLのイメージ
SQLのイメージ

3-2 intersect allを模倣

 次は、intersect allを模倣するSQLです。テーブルのデータと、出力結果を考えます。

tbl_A
ColA
1
1
2
2
3
tbl_B
ColA
1
2
2
3
3

 下記のintersect allを模倣します。

select ColA from tbl_A
intersect all
select ColA from tbl_B;
出力結果
ColA
1
2
2
3

 intersect allを実装する上でのポイントは、重複する要素があったときに要素の数を考慮する点です。要素の数を考慮することに注目すると、答えは下記となります。

intersect allを模倣
select ColA
from (select ColA,Row_Number() over(partition by ColA order by 1) from tbl_A
      intersect
      select ColA,Row_Number() over(partition by ColA order by 1) from tbl_B);

 minus allを模倣する方法と同じ考え方で、Row_Number関数で各要素に連番をつけてからintersectを使い、intersect allと同じ結果を取得しています。

 SQLのイメージは、さきほどのminus allと同じで下記となります。赤線がpartition byのイメージで、緑線がintersectによる出力する制御のイメージです。

SQLのイメージ
SQLのイメージ

3-3 「2つのテーブルが相等か」を判定するクエリ(重複行を考慮)

 以上により、minus allを模倣するSQLを使う、重複行を考慮した「2つのテーブルが相等か」を判定するクエリは、下記となります。

結果が0件なら「等しい」、1件以上なら「異なる」(重複行を考慮)
select count(*) over(),ColA,
Row_Number() over(partition by ColA order by 1) from tbl_A
 minus
select count(*) over(),ColA,
Row_Number() over(partition by ColA order by 1) from tbl_B;

 テーブルが複数列(ColA,ColB,ColC)なら下記となります。

select count(*) over(),ColA,ColB,ColC,
Row_Number() over(partition by ColA,ColB,ColC order by 1) from tbl_A
 minus
select count(*) over(),ColA,ColB,ColC,
Row_Number() over(partition by ColA,ColB,ColC order by 1) from tbl_B;

次のページ
4. 重複を除いた累計

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
分析関数の衝撃連載記事一覧

もっと読む

この記事の著者

山岸 賢治(ヤマギシ ケンジ)

趣味が競技プログラミングなWebエンジニアで、OracleSQLパズルの運営者。AtCoderの最高レーティングは1204(水色)。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1594 2008/10/07 19:35

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング