- PR -

1:nでサブ情報があるデータの一覧表示をするには

1
投稿者投稿内容
しろくま
常連さん
会議室デビュー日: 2004/10/15
投稿数: 35
投稿日時: 2007-08-20 22:08
お世話になります、しろくまです。

環境
PostgreSQL8.1

良く見かける飲食店ポータルサイトのように、店舗の基本情報以外にサブ情報(ジャンル、こだわり、クーポンなど)がn件ある情報付加してを店舗を一覧形式で表示するにはどのようにデータ取得を行えばよいのでしょうか?

以下、テーブル構成です。
店舗マスタ
 ・店舗番号
 ・店舗名称
 ・etc

クーポン情報
 ・クーポン番号
 ・店舗番号
 ・クーポン内容
1:nで店舗番号でリンクしています。

これを単に、
select 店舗マスタ.店舗名称,クーポン情報.クーポン内容
LEFT JOIN クーポン情報 ON クーポン情報.店舗番号 = 店舗マスタ.店舗番号
としてしまうと、

店舗A | クーポンX |
店舗A | クーポンY |
店舗A | クーポンZ |
店舗B | クーポンN |

これだと、店舗情報がブレイクするまで読み飛ばした後、次の店舗を表示になってしますので、今のご時勢そんな方法は無いかと...

そこで、何とか以下のような形で取得出来れば、すんなり表示出来るのではと思ってます。

店舗A | クーポンX | クーポンY | クーポンZ | 
店舗B | クーポンN |  

それとも、根本的に考え方が間違っているのでしょうか?
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-08-20 22:32
引用:

しろくまさんの書き込み (2007-08-20 22:08) より:
店舗A | クーポンX |
店舗A | クーポンY |
店舗A | クーポンZ |
店舗B | クーポンN |


この形でSELECTして表示する側で加工しましょう。
SQLでは列方向に(列数を)可変にすることは出来ません。

SELECT句に最大クーポン数まで取得するように
サブクエリを並べれば不可能ではないと思いますが、
おぞましく汚いクエリ&むしろ手間が増えるでしょう。

#その前にROWNUMのないPostgreSQLで出来るんだろうか?
忠犬
大ベテラン
会議室デビュー日: 2006/05/01
投稿数: 109
投稿日時: 2007-08-21 02:48
横方向に表示する項目数を可変にするというのは、SQLで行おうとすると相当に困難
であり、仮にできても冗長で性能も出せないSQLになってしまいます。
項目数の上限を決めてしまえば、ちょっと小細工が入っていますが、一応は希望に近い
結果を得られます。

1.表定義
「クーポン情報」表の「クーポン番号」列は、店舗内での通番にしています。

コード:
create table 店舗マスタ
(店舗番号    int         primary key, 
 店舗名称    varchar(20), 
 etc         varchar(100)); 
create table クーポン情報 
(店舗番号     int,
 クーポン番号 int, 
 クーポン内容 varchar(30),
 primary key(店舗番号,クーポン番号));



2.格納データ
コード:
insert into 店舗マスタ values(101,'店舗A',null);
insert into 店舗マスタ values(201,'店舗B',null);
insert into 店舗マスタ values(301,'店舗C',null);
insert into 店舗マスタ values(401,'店舗D',null);
insert into 店舗マスタ values(501,'店舗E',null);

insert into クーポン情報 values(101,1,'クーポンA-1');
insert into クーポン情報 values(101,2,'クーポンA-2');
insert into クーポン情報 values(101,3,'クーポンA-3');
insert into クーポン情報 values(201,1,'クーポンB-1');
insert into クーポン情報 values(401,1,'クーポンD-1');
insert into クーポン情報 values(401,2,'クーポンD-2');
insert into クーポン情報 values(401,3,'クーポンD-3');
insert into クーポン情報 values(401,4,'クーポンD-4');
insert into クーポン情報 values(401,5,'クーポンD-5');
insert into クーポン情報 values(501,1,'クーポンE-1');



3.検索
 店舗毎に対応するクーポン情報を横に並べるため、「店舗番号」列でグループ化
 (group by)しますが、そうするとgroup byで指定した列、集合(集計)関数しか
 指定できないため、意味のないmax関数を使ってエラー回避するという小細工を
 行っています。
 また、横に並べて表示するクーポン数は、最大で6個に固定しています。
 
コード:
select
  店舗名称,
  c.クーポン1,
  c.クーポン2,
  c.クーポン3,
  c.クーポン4,
  c.クーポン5,
  c.クーポン6
 from 店舗マスタ as s
  left join (select
               店舗番号,
               max(case クーポン番号 when 1 then クーポン内容 else null end) as クーポン1,
               max(case クーポン番号 when 2 then クーポン内容 else null end) as クーポン2,
               max(case クーポン番号 when 3 then クーポン内容 else null end) as クーポン3,
               max(case クーポン番号 when 4 then クーポン内容 else null end) as クーポン4,
               max(case クーポン番号 when 5 then クーポン内容 else null end) as クーポン5,
               max(case クーポン番号 when 6 then クーポン内容 else null end) as クーポン6
              from クーポン情報
              group by 店舗番号) as c
   on s.店舗番号=c.店舗番号
 order by s.店舗番号;



もう少し美しくできないかとも思ったのですが、今夜は疲れてしまいました。
しろくま
常連さん
会議室デビュー日: 2004/10/15
投稿数: 35
投稿日時: 2007-08-21 11:39
お世話になります、しろくまです。

あしゅさん、忠犬さんレスありがとう御座います。
忠犬さんには、サンプルまでご提示していただき申し訳御座いません。

やはり、SQLで横方向へのデータ取得は無理があるみたいですね。
クーポン情報に限りませんが、サブとなる情報の件数になるべく上限値は設けないようにしたいと思っています。

もうちょっと、違った方向で検討して見ます。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-08-21 14:17
引用:

しろくまさんの書き込み (2007-08-20 22:08) より:
これだと、店舗情報がブレイクするまで読み飛ばした後、次の店舗を表示になってしますので、今のご時勢そんな方法は無いかと...


リレーショナルDB(RDB) を使う以上、SQL で得られる結果セットも RDB の枠組みに沿ったものであるべきだと考えます。そうなると、結果の列に、「クーポンX」、「クーポンY」、「クーポンZ」のように横方向に伸びる繰り返しがあるのはおかしい、と考えることができます。

古臭いですが、キーブレークを使うのが正攻法だと思います。もしアプリケーションの側でキーブレークを使わないとしたら、ミドルウェアでそういう機能を持つこともあっても良いと思います。しかし、少なくとも SQL や結果セットの段階で、列の繰り返しがあるのは上述のように RDB から外れるのでしょう。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
カーニー
ぬし
会議室デビュー日: 2003/09/04
投稿数: 358
お住まい・勤務地: 東京
投稿日時: 2007-08-21 15:41
結果が大きければ勧めませんが、ジョインしないというソリューションもあります。

つまり、外側のループで、店舗マスタからのSELECTカーソルを回して、内側のループでクーポン情報からのSELECTカーソルを回すということです。

アプリ-DB間のラウンドトリップが増えるし、SQLコール回数も増えるので、非効率ではありますが。
しろくま
常連さん
会議室デビュー日: 2004/10/15
投稿数: 35
投稿日時: 2007-08-22 08:57
お世話になります、しろくまです。

unibonさん、カーニーさんレスありがとう御座います。

やはり、RDBの作法に合わないようですね。
初心に戻り、お二方のご助言の方向で行ってみます。
それほどデータ量も多くないので、I/Oが増えても大丈夫かなぁと

1

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