ようこそ ゲスト さん、新規登録(無料)して気になる疑問を解決しませんか?

質問

QNo.4005627 SQL文について
質問者:ieeek2008 OracleやSQLについてはまだ初心者のレベルで理解が浅いので言葉足らずかもしれませんがよろしくお願いします。
以下のようなテーブル(名称:TBL)があったとします。
SHOP_CODE------SHOP_NUMBER----MONEY1------MONEY2
A ---------------- 1 ---------------- 100 ------------- 200
B ---------------- 2 ---------------- 300 ------------- 400
C ---------------- 3 ---------------- 500 ------------- 600
D ---------------- 4 ---------------- 700 ------------- 800

例えば、SHOP_CODEがA〜Dのどれかの行(レコード)はそのまま抽出して、残った行(レコード)はMONEY1およびMONEY2を0に変更して抽出しようとした場合、

SELECT * FROM TBL WHERE SHOP_CODE = 'ここはA〜Dのどれかを代入'
UNION SELECT SHOP_CODE, SHOP_NUMBER, 0, 0 FROM TBL WHERE SHOP_CODE <> 'A〜Dのどれかを代入'

このようなSQL文を考えてみました。
しかし、比較的簡単な例ならばよいのですが、UNION前のSELECT文が複雑になってきた場合のことを考え以下のような文の作りかたができないかと思いました。

SELECT * FROM TBL WHERE SHOP_CODE = 'ここはA〜Dのどれかを代入'・・・『この時点で抽出した塊になんらかの名称をつける(例:tbl)』
UNION SELECT SHOP_CODE, SHOP_NUMBER, 0, 0 FROM TBL WHERE SHOP_CODE <> tbl.SHOP_CODE・・・『このようにUNION以前に抽出した塊の名称を利用して条件を作成』

このような方法ができるとした場合、前段階で抽出した塊にどのような方法で名称をつけるのか分かりませんでした。(汗)そもそもできるかどうかもわかりませんが、、、(^^;
最初のSQL文がベターな方法なのかも分かりませんが、上記に示した方法で抽出することが可能でしょうか?もしできるのならば、前述したように名称をつけて条件を作成する方法等を教えていただきたいと思います。
おおよそ話を分かっていただければよいのですが、ものすごく簡単に言うと一つのテーブルのある行とある行に別々の処理をして再構成したいというようなイメージです。(今回はMONEYを0にすると仮定しました)
できれば上記の方法に沿った考えで回答をいただけると私も助かりますが、もっと良い方法があれば是非伺いたいと思います。お時間の方ありましたらよろしくお願いします。
困り度:
  • すぐに回答を!
質問投稿日時:
08/05/08 00:12
この質問に対する回答は締め切られました。

回答良回答20pt

ANo.3 >前半のSELECT文で抽出したレコードの集まりを表として名前を付け
言っている意味が良く分かりません。

ただ、クエリをFROM句に使うことが可能です。
例えば、以下のようにします。
SELCT SHOP_CODE,SHOP_NUMBER,MONEY1,MONEY2 FROM
 (SELECT SHOP_CODE,SHOP_NUMBER,MONEY1,MONEY2 FROM TBL WHERE SHOP_CODE BETWN 'A' AND 'D'),
 (SELECT SHOP_CODE,SHOP_NUMBER,0 MONEY1,0 MONEY2 FROM TBL WHERE SHOP_CODE NOT IN ('A','B','C','D'))

結合条件が無いので、レコード数は両クエリのレコード数の積(和ではない)になりますが、
こういう記述も可能だというサンプルです。レコード数が大量にあるテーブルの場合は
このように条件で絞ったクエリをFROM句で使うとにより、処理速度の向上が期待できる場合があります。
特にキー項目で絞れる場合は大きな効果が得られます。
まあ、DBシステムにより、色々なワザがあるわけで、覚えておいても損はないでしょう。
回答者:nda23
種類:アドバイス
どんな人:専門家
自信:参考意見
回答日時:
08/05/08 22:19
この回答へのお礼再度のご回答ありがとうございます。うーんどうやら、すこしばかり私自身の考えがまとまっていなかったかな、、、(汗)検討違いな質問をしてしまったようで申し訳ないです。ただ、回答していただいたクエリをFROM句に使う・・・で示していただいたSQL文は私の思っていたモノに近いようです。参考にさせていただきます。もうすこし、勉強して私自身の能力を引き上げてれるよう努力してみます。お忙しい中、お付き合いいただきありがとうございました。(^^)

回答

ANo.2 Oracleのバージョンが9i以上の場合は以下の構文になります。
SELECT SHOP_CODE,SHOP_NUMBER,
 CASE WHEN SHOP_CODE BETWEEN 'A' AND 'D' THEN MONY1 ELSE 0 END MONY1,
 CASE WHEN SHOP_CODE BETWEEN 'A' AND 'D' THEN MONY2 ELSE 0 END MONY2
FROM TBL

【参考】
(1)UNIONクエリは遅いので、なるべく使用しない。
(2)式評価回数を減らす。
 SHOP_CODE>='A' AND SHOP_CODE<='D' → SHOP_CODE BETWEEN 'A' AND 'D'
 SHOP_CODEの出現回数を減らす。連続値でなければINを使う。
(3)大文字小文字を統一する。
 SHOP_CODE BETWEEN 'A' AND 'D' でも shop_code BETWEEN 'A' AND 'D' でも
 結果は同じだが、混在させると最適化されない。

昔はマシン性能も悪く、Oracleのエンジンが相当に馬鹿だったので、
SQLの書き方にも工夫が必要でした。最近はマシンも速いし、エンジンも
かなり利口になったようで、上記のような工夫に神経質になることも
ないと思いますが、オマジナイ程度には役に立つかも知れません。
回答者:nda23
種類:アドバイス
どんな人:専門家
自信:参考意見
回答日時:
08/05/08 09:22
この回答へのお礼ご回答ありがとうございます。(^^)内容読ませていただきました。【参考】は素人の私にとって、とてもためになる内容でした。UNIONはあまり使用しないほうがよいのですネ。こうなると私の考えは一から構築しなおした方がよいみたいですネ。(^^;
CASE演算子ならば、比較的複雑な分岐を行うことができようですネ。勉強になりました。この方法もいろいろと試してみようと思います。

すこし、話を質問に戻してしまいます。UNIONについてになってしまうのですが、、、(^^;内容がまた重複してしまうようで申し訳ないですが、
SELECT ○○○○〜〜 UNION SELECT △△△△〜〜
のような文を用いた場合、前半のSELECT文で抽出したレコードの集まりを表として名前を付け、後半のSELECT文の中で使用できるか?という質問に関してはいかがでしょうか?もしご意見がございましたら時間のある限りでかまいませんのでよろしくお願いします。ホント理解が浅くて質問がどうも中途半端で申し訳ないですが、、、(泣)またこの場を借りてNO.1の方や他の方のご意見もまだお待ちしております。

回答良回答10pt

ANo.1 SELECT SHOP_CODE, SHOP_NUMBER
, DECODE(SHOP_CODE, 'A', MONEY1, 0) MONEY1
, DECODE(SHOP_CODE, 'A', MONEY2, 0) MONEY2
FROM TBL
これじゃダメ?
回答者:unamana19
種類:アドバイス
どんな人:一般人
自信:参考意見
回答日時:
08/05/08 08:14
この回答へのお礼ご回答ありがとうございます。(^^)ようやく返事をする時間ができました。(^^;
なるほどDECODE関数を使用するわけですか。私もこの回答を見てすこし調べました。条件によって分岐させることができるわけですネ。これならば、シンプルな文でよいと思います。ただ、一つ気になるのはもし、分岐条件が複雑になってきた場合は(今回はAの場合とそれ以外という分けだと思いますが)第1の引数と第2の引数('A'の箇所)に分岐条件の式などを書いたりもできるのかななんて思いました。
そういえば疑問が浮かんだので書き込んでおきます、、、。回答された文の中にはDECODE(○○○○)MONEY1と表記がありますが、MONEY1という表記はいりますかネ?私の調べた感じだと表記はいらないかもなんて思ったもので、、。それとも分かりやすいように明示的に書いていただいたのかな?(^^)もしくはそう書くこともできるとか?私の方でいろいろ試してみます。
朝早くから回答していただきありがとうございました。m(_ _)m