質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Oracle

Oracleは、米オラクルが取り扱うリレーショナルデータベース管理システムです。メインフレームからPCまで、多様なプラットフォームに対応しています。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

3回答

2601閲覧

Oracleの外部結合(+)を用いたSQLを、通常のSQLで書き直したい。

kutunesirka

総合スコア13

Oracle

Oracleは、米オラクルが取り扱うリレーショナルデータベース管理システムです。メインフレームからPCまで、多様なプラットフォームに対応しています。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2019/01/12 09:37

前提・実現したいこと

現在、Oracleに向けているシステムを、PostgreSQL用に設計し直すという作業をしています。
そのため、システムが発行しているSQLクエリを、PostgreSQLに書き直しているのですが、どうすれば良いのか分からないSQLがあり、それについて質問させていただければと思います。

発生している問題

以下のようなOracleの外部結合(+)を使って、色々と結合させているSQLがあります。

sql

1select 2 a.column_1 as DATA01 3 b.column_3 as DATA02 4 c.column_7 as DATA03 5 d.column_2 as DATA04 6from 7 AA as a, 8 BB as b, 9 (select .... from CC) as c, 10 (select .... from DD) as d 11where 12 a.column_3 = c.column_3(+) 13 a.column_4 = c.column_4(+) 14 , b.column_3 = c.column_3(+) 15 , c.column_3 = d.column_3(+) 16 , c.column_4 = d.column_4(+) 17 , c.column_6 < 21

このSQLは、このように、from句で副問合せが使われたテーブルを、外部結合で何度も利用しています(「c」とエイリアスが付けられた副問合せが、where句で、いくつも結合に使用されている事を意味します)。

これをPostgreSQLなどで動く、普通の外部結合(LEFT OUTER JOIN)を使って書き直すには、どうすれば良いのか、分かりますでしょうか?

試したこと

一応、以下のように書いてみましたが、(案の定というか当たり前ですが)同じエイリアスは設定できないと怒られてしまいます。

sql

1select 2 a.column_1 as DATA01 3 b.column_3 as DATA02 4 c.column_7 as DATA03 5 d.column_2 as DATA04 6from 7 AA as a LEFT OUTER JOIN (select .... from CC) as c on a.column_3 = c.column_3 8 LEFT OUTER JOIN (select .... from CC) as c on a.column_3 = c.column_3 9 , BB as b LEFT OUTER JOIN (select .... from CC) as c on b.column_3 = c.column_3 10 ...... 11 ...... 12 ...... 13where 14 c.column_6 < 21

以下のように、それぞれエイリアスを異なる名前にすると、エラーは起きなくなりますが、やはり出力されるデータは、元のSQLと異なってしまいますよね?

sql

1select 2 a.column_1 as DATA01 3 b.column_3 as DATA02 4 c.column_7 as DATA03 5 d.column_2 as DATA04 6from 7 AA as a LEFT OUTER JOIN (select .... from CC) as c_01 on a.column_3 = c_01.column_3 8 LEFT OUTER JOIN (select .... from CC) as c_02 on a.column_3 = c_02.column_3 9 , BB as b LEFT OUTER JOIN (select .... from CC) as c_03 on b.column_3 = c_03.column_3 10 ...... 11 ...... 12 ...... 13where 14 c_01.column_6 < 21

出力結果をOracleのときと同じにするために、どうにか、「エイリアスを設定している副問合せ」を、「c」のエイリアスは維持したまま、使い回せるような書き方をしたいのですが、うまいSQLが思いつきません。
何か案はありますでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Orlofsky

2019/01/12 09:51

質問にCREATE TABLE も追記した方が適切なコメントが付き易いです。
kutunesirka

2019/01/15 20:26

ちょっと考えてみたのですが、大本のSQL自体が300行くらいある代物で、その一部を抜き出す形で質問させていただいたので、ちょっとCREATE文を失念していました。 今後、質問するときは、その辺りも気をつけてみようと思います。 ご指摘、ありがとうございます。
guest

回答3

0

皆様、ありがとうございます。
色々とSQLで調査していた所、WITHを使うと思ったとおりのSQLが書けました。
(テストもしてみた所、出力結果は、Oracleの時と同様に出力されました)

sql

1WITH 2 a as (select * from AA) 3 , b as (select * from BB) 4 , c as (select .... from CC) 5 , d as (select .... from DD) 6select 7 a.column_1 as DATA01 8 b.column_3 as DATA02 9 c.column_7 as DATA03 10 d.column_2 as DATA04 11from 12 a LEFT OUTER JOIN c on a.column_3 = c.column_3 and a.column_4 = c.column_4 13 LEFT OUTER JOIN c on b.column_3 = c.column_3 14 LEFT OUTER JOIN d on c.column_3 = d.column_3 and c.column_4 = d.column_4 15where 16 c.column_6 < 21

こいつで、一旦は進めていこうと思います。ありがとうございました。
(結合の2行目の「LEFT OUTER JOIN c on b.column_3 = c.column_3」は、ひょっとしたら「LEFT OUTER JOIN b on c.column_3 = b.column_3」とすべきなのかもしれませんが)

投稿2019/01/15 20:32

編集2019/01/16 17:28
kutunesirka

総合スコア13

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sazi

2019/01/16 00:12

withはSQLはを括ることができて、可読性やレスポンスを高めます。 ですが、関係性において一筆書きするのと変わりはありません。 ですので、「withにしたからできた」ではありませんので、お間違えの無きよう。
sazi

2019/01/16 00:22 編集

where c.column_6 < 21 の部分でcは外部結合なので、nullが発生しますが除外されます。 結果、等結合と同じになります。 「見直しを」という理由の一部です。
sazi

2019/01/16 00:24

a LEFT OUTER JOIN c on a.column_3 = c.column_3 LEFT OUTER JOIN c on a.column_3 = c.column_3 LEFT OUTER JOIN c on b.column_3 = c.column_3 上記のCはas C1とかでエイリアス付けてますよね? というか、そうしないとエラーのはずですし
kutunesirka

2019/01/16 17:33 編集

> ですので、「withにしたからできた」ではありませんので、お間違えの無きよう。 withについても、指摘いただいた内容で理解しております。 > cは外部結合なので、nullが発生しますが除外されます。 where c.column_6 < 21の部分は、あまり考えずに(元のSQLに、似たような感じで絞り込み条件があったので)追加しています。基本的に、この部分は残しておくつもりです(今回の改修では、SQLは可能な限り、そのまま残すのが要件となっていますので)。 > 上記のCはas C1とかでエイリアス付けてますよね? はい、エイリアスは付けております。つけるのを忘れておりました。 なお、テストを繰り返してみると、左と右のテーブルが同じ場合は、「a LEFT OUTER JOIN c on a.column_3 = c.column_3 and a.column_4 = c.column_4」というように、andで結んでやる必要があったようですので、今回はエイリアスがそもそも不要でした。 ご指摘、ありがとうございました。 ↑のSQLも、そのように修正しております。
guest

0

完全ではないですが、こんなイメージで。

select a.column_1 as DATA01 b.column_3 as DATA02 c.column_7 as DATA03 d.column_2 as DATA04 from AA as a join BB as b on a.~~ = b.~~ and ~~~ left join ( select .... from CC ) as c on a.column_3 = c.column_3 and a.column_4 = c.column_4 left join ( select .... from DD ) as d on ~~~~ where

該当行がないことが起こりうるのがCとdということであれば、
aやbのカラムとからめていかないとけなくて、
cとdのカラムで結合させようとすると破綻します。
aやbとc、aやbとdの組み合わせで見直ししてください。

投稿2019/01/12 09:54

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kutunesirka

2019/01/14 16:51

OracleのSQLをトレースするようなイメージで組んだ方が安全かなと思いましたが、やはり細かく出力結果を見ながら、結合させていったほうが良い感じなんでしょうかね? いろいろと試してみます。ありがとうございます。
guest

0

ベストアンサー

元のSQLの関係を再現すると以下になります。
※bとcの関係は確認した方が良いですね。
追記&修正
c.column_6 < 21は結合条件ではないような。
だとするとCの抽出に含めた方が関係は崩さないですみそうですけど。
※結果が変わる(取得が多くなる)ならそもそも外部結合じゃなかったということで

SQL

1select 2 a.column_1 as DATA01 3 b.column_3 as DATA02 4 c.column_7 as DATA03 5 d.column_2 as DATA04 6from 7 AA as a 8 left join (select .... from CC where column_6 < 21) as c 9 on a.column_3 = c.column_3 and a.column_4 = c.column_4 10 left join (select .... from DD) as d 11 on c.column_3 = d.column_3 and c.column_4 = d.column_4 12 right join BB as b 13 on b.column_3 = c.column_3

投稿2019/01/12 09:52

編集2019/01/12 10:19
sazi

総合スコア25184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/01/12 09:54

saziさん、はやぃ~
sazi

2019/01/12 10:05 編集

早いだけでしたー
kutunesirka

2019/01/14 16:50

ありがとうございます。 やはり完全にOracleのSQLをトレースするようなイメージではなく、細かく出力結果を見ながら、結合させていったほうが良い感じなんでしょうかね? いろいろと試してみます。
sazi

2019/01/15 00:12

構文の解釈という意味では実現できていると思うんですけど、リレーション自体が「本当に?」みたいな印象です。 本来の要件に立ち返って見直すべきSQLだと思いますよ。 そうすれば無駄な結合(本来は等結合で良い部分とか)がなくなれば高速にもなるでしょうし。
kutunesirka

2019/01/15 20:24

ご指摘、ありがとうございます。 確かに、作られたのが10年近く前のかなり古いシステムなので、テーブル構成などがかなり凄まじい作りになっています。 なので、時間があれば見直すべきなのでしょうが、今回の要件は、あくまでOracleからPostgreSQLの移行だけなので、テーブル構成は変えずに進めていっております。 いろいろと調べた所、WITHを使うと、上手くいきそうだったので、それで進めてみようと思います。
Orlofsky

2019/01/15 22:08

10年くらい前ですと、FROMにはテーブルまたはビューを1つしか記述してはならない、SELECTの並びには * 以外を記述してはならない、ってSQL入門レベルのスキルがない人が作ったコーディング規約を厳守させていた大手SIerがありました。
sazi

2019/01/16 00:19

join禁止という規約で揉めた事があります。 理由は条件が纏まっていて見やすいという事でした。
Orlofsky

2019/01/16 03:04

Oracleに関してなら、 9.2 の最終パッチで JOIN のバグが解消できたかどうかでしたから、JOIN 禁止が妥当ですが、10g 以降で JOIN を使いたくないという人には正規マニュアルをきちんと読ませて叩き直すか、叩き出すかのどちらかで。
kutunesirka

2019/01/16 17:39

もう10年くらい前のシステムなので、当初はまだjoin禁止だったのかもしれません……と思って色々と調べてみると、普通にjoinを使ってる箇所もあり、かと思うと内部結合もWHERで書いてる箇所もあり、どうもその辺りが統一されずに書かれたシステムのようです。 とりあえず、PostgreSQLに向けるとエラーを起こす箇所を修正するのが、今回の要件なので、普通に動いてる箇所はそのままにしておきます(無論、テストはしますが)。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問