- PR -

クロス集計のサブクエリ、内部結合

投稿者投稿内容
tamao30
常連さん
会議室デビュー日: 2004/11/16
投稿数: 34
投稿日時: 2006-02-07 00:25
お世話になります。

ORACLEでクロス集計のSQLを作ったのですが、
OptionType=2で条件抽出してあることにより、販売日時(行見出し)が
合計データがない日付が飛ばされてしまいます。
下の表の販売日時を連続(2006/1/1〜1/10)で表示したいのですが、
クロス集計の場合は無理でしょうか?

SELECT to_char(SaleTime,'yyyy/mm/dd') "販売日時",
sum(decode(Genre,'Science',Price,'0')) "科学",
sum(decode(Genre,'Language',Price,'0')) "語学",
sum(decode(Genre,'History',Price,'0')) "歴史"
FROM TBL_BOOKS
WHERE OptionType = 2
AND IssueDate >= '2006/1/1' AND IssueDate < '2006/1/10'
GROUP BY to_char(SaleTime,'yyyy/mm/dd')


販売日時  科学  語学  歴史
------- ---- ---- ----
2006/1/2 5000 3500 2800
2006/1/5 1500 800 400
2006/1/7 7100 0 2000
2006/1/8 2100 5000 0
2006/1/9 1000 1200 450

OptionType=2を省いたSelect文
をサブクエリにしてためしてみましたが、実行できません。
下記の2つのSELECT文を別テーブルにしてJOINするのは成功しました。
1つのSQLにまとめたいのですが、良い方法はありますでしょうか?

SELECT to_char(ASaleTime,'yyyy/mm/dd') "販売日時",
sum(decode(A.Genre,'Science',A.Price,'0')) "科学",
sum(decode(A.Genre,'Language',A.Price,'0')) "語学",
sum(decode(A.Genre,'History',A.Price,'0')) "歴史"
FROM TBL_BOOKS A, TBL_BOOKS B
WHERE A.OptionType = 2
AND A.IssueDate >= '2006/1/1' AND A.IssueDate < '2006/2/1'
AND to_char(A.SaleTime,'yyyy/mm/dd')
= (SELECT to_char(B.SaleTime,'yyyy/mm/dd') FROM TBL_BOOKS B
GROUP BY to_char(B.SaleTime,'yyyy/mm/dd'))
GROUP BY to_char(A.SaleTime,'yyyy/mm/dd')

よろしくお願いいたします。

[ メッセージ編集済み 編集者: tamao30 編集日時 2006-02-07 00:25 ]
ゆいたん
ベテラン
会議室デビュー日: 2004/08/26
投稿数: 91
投稿日時: 2006-02-07 10:08
こんにちは

コード:

create table a(a1 date,a2 number,a3 number);
insert into a values('2006/1/1',1,100);
insert into a values('2006/1/1',2,1000);
insert into a values('2006/1/4',1,100);
insert into a values('2006/1/5',3,3000);
create table b(b1 date);
insert into b values('2006/1/1');
insert into b values('2006/1/2');
insert into b values('2006/1/3');
insert into b values('2006/1/4');
insert into b values('2006/1/5');

select
b1
, sum(decode(a2,1,a3,0)) x1
, sum(decode(a2,2,a3,0)) x2
, sum(decode(a2,3,a3,0)) x3
from
(select b1,a2,a3 from a,b where b.b1 = a.a1(+))
group by
b1
;

B1 X1 X2 X3
-------- ---------- ---------- ----------
06-01-01 100 1000 0
06-01-02 0 0 0
06-01-03 0 0 0
06-01-04 100 0 0
06-01-05 0 0 3000



日付の候補を持って外部結合を行えばよいのではないでしょうか。
すぐに浮かんだのはこんな方法です。

以上

[ メッセージ編集済み 編集者: ゆいたん 編集日時 2006-02-07 10:09 ]
tamao30
常連さん
会議室デビュー日: 2004/11/16
投稿数: 34
投稿日時: 2006-02-07 11:14
ありがとうございます。

ACCESSのパススルークエリなどからもSQLを発行したいので、CREATE TABLEをせずに、
1つのSELECT文にしたいのですが、どうも自己結合やサブクエリを使ってもうまくいきません。

つまり、aテーブルに格納してあるdateを条件に使いたいのですが、どうしたらよろしいでしょうか?
今川 美保(夏椰)
ぬし
会議室デビュー日: 2004/06/10
投稿数: 363
お住まい・勤務地: 神奈川県茅ヶ崎市
投稿日時: 2006-02-07 11:54
ゆいたんさんとちょろっと違ったパターンで。

DateTblクエリは存在する日付の一覧を取得するSQL
PriceTblクエリは日付・項目ごとの金額合計値を取得するSQL

上記2点のSQLを日付でOuterJoinしました。
PriceTblのクエリで金額計算対象となるデータを絞り込んでおけば良いかと思います。

コード:

WITH DateTbl AS (
  SELECT distinct saletime FROM tbl_books 
),
PriceTbl AS (
	SELECT 
		SaleTime,
		SUM(DECODE(Genre,'Science',Price,'0')) col1,
		SUM(DECODE(Genre,'Language',Price,'0')) col2,
		SUM(DECODE(Genre,'History',Price,'0')) col3 
	FROM TBL_BOOKS
	WHERE
		OptionType = 2
		AND IssueDate >= TO_DATE('20060101','yyyymmdd') AND IssueDate < TO_DATE('20060201','yyyymmdd')
	GROUP BY SaleTime
)
SELECT 
	TO_CHAR(DateTbl.SaleTime),
	NVL(PriceTbl.col1,0) "Science",
	NVL(PriceTbl.col2,0) "Language",
	NVL(PriceTbl.col3,0) "History" 
FROM 
	DateTbl LEFT OUTER JOIN PriceTbl ON DateTbl.SaleTime = PriceTbl.SaleTime ;


tamao30
常連さん
会議室デビュー日: 2004/11/16
投稿数: 34
投稿日時: 2006-02-07 20:01
ありがとうございます。

やっぱり、ACCESSのパススルーからでは、定義的なコマンドは使えないようで、
WITHでテーブルを定義するのは、出来ないようです。

ご両人に教えていただいたSQLを参考に、組み合わせながらいろいろ試しているところですが、select文1つで出来る案がございましたら、よろしくお願いいたします。
今川 美保(夏椰)
ぬし
会議室デビュー日: 2004/06/10
投稿数: 363
お住まい・勤務地: 神奈川県茅ヶ崎市
投稿日時: 2006-02-08 09:44
引用:

tamao30さんの書き込み (2006-02-07 20:01) より:
ありがとうございます。

やっぱり、ACCESSのパススルーからでは、定義的なコマンドは使えないようで、
WITHでテーブルを定義するのは、出来ないようです。



オレの環境は
Access2000+Oracle9iR2ですが、
「投稿日時: 2006-02-07 11:54」で提示したSQLを
パススルークエリでできることは確認しています。

tamao30さんがお使いの環境をあげてみては如何でしょう?
それにより制限が出てきているかもしれませんので。
tamao30
常連さん
会議室デビュー日: 2004/11/16
投稿数: 34
投稿日時: 2006-02-08 11:42
ありがとうございます。

oracleのバージョンは10g
ACCESSは2003です。

エラーメッセージ:
「ReturnsRecordsプロパティがTrueに設定されているパススルークエリーから
レコードが返されませんでした。」
が出てしまいます。

DateTblとPriceTblを別個に実行すると正常でした。
定義コマンドの問題ではなく、データの中身の問題でしょうか?
今川 美保(夏椰)
ぬし
会議室デビュー日: 2004/06/10
投稿数: 363
お住まい・勤務地: 神奈川県茅ヶ崎市
投稿日時: 2006-02-08 12:43
引用:

tamao30さんの書き込み (2006-02-08 11:42) より:
ありがとうございます。

oracleのバージョンは10g
ACCESSは2003です。

エラーメッセージ:
「ReturnsRecordsプロパティがTrueに設定されているパススルークエリーから
レコードが返されませんでした。」
が出てしまいます。

DateTblとPriceTblを別個に実行すると正常でした。
定義コマンドの問題ではなく、データの中身の問題でしょうか?



え〜〜と、確認ですが
SQL自体はSQL*Plusなどで実行して目的とするデータは取得できていますか?

エラーメッセージの内容から、クエリが結果を返さないのに
ReturnsRecordsプロパティの値をTrueにしていると出るみたいなのですが、
このプロパティをFALSEにするのは更新系SQLの時みたいなので
念のための確認です。

パススルーは構文チェックをせず接続先へSQLを投げるみたいなので、
SQL*Plusなどで実行できれば基本的には通ると思うのですが・・・。

Access2003もOracle10gも今の環境に入れられないので、
ネットで調べてみたりした内容からの憶測に過ぎませんが・・・・。

スキルアップ/キャリアアップ(JOB@IT)