|
Count を 使った ソースコードを紹介する表示色の説明:ASP VBScriptは <% 〜 %> キーワードはCount です。
<%@LANGUAGE=VBScript%>
<html>
<head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=x-sjis">
<title>SQL サブクエリーの埋め込み(Select文のネスト)</title>
</head>
<body>
<h1>三流君:SQL サブクエリーの埋め込み(Select文のネスト)</h1>
イヤになるくらい、Select文を重ねてみます(多重・ネスト)<br>
<h2>質問とテストデータの準備</h2>
いただいた質問は、<br>
------<br>
アクセスあるいはエクセルで以下のように横方向へ展開したいのですが、WEB上を色々検索したのですが、これといった方法が見つかりませんでした。やはりムリなのでしょうか?<br>
<br>
●元データ<br>
顧客 購入商品<br>
顧客1 商品A<br>
顧客1 商品B<br>
顧客2 商品B<br>
顧客2 商品C<br>
顧客3 商品A<br>
<br>
●展開イメージ<br>
顧客1 商品A・商品B<br>
顧客2 商品B・商品C<br>
顧客3 商品A<br>
------<br>
db105.mdbにテスト用のT_DATAテーブルを作成しました。<br>
<%
strSQL = "Select * From T_DATA"
Call RUN_SQL(strSQL) 'テストデータの表示
%>
<h2>購入商品に順位を付けるSQLを作成</h2>
Count関数を使用して、順位を付けてみた。<br>
<pre>strSQL = "Select ID, 顧客, 購入商品, "
strSQL = strSQL & " (Select Count(*) From T_DATA AS T_TEMP "
strSQL = strSQL & " Where T_TEMP.顧客 = T_DATA.顧客 "
strSQL = strSQL & " And T_TEMP.購入商品 < T_DATA.購入商品) AS 順位"
strSQL = strSQL & " From T_DATA"</pre>
↑こんな感じで、Select文の中に結果を返すSelect文を書くことができます<br>
<%
strSQL = "Select ID, 顧客, 購入商品, "
strSQL = strSQL & " (Select Count(*) From T_DATA AS T_TEMP "
strSQL = strSQL & " Where T_TEMP.顧客 = T_DATA.顧客 "
strSQL = strSQL & " And T_TEMP.購入商品 < T_DATA.購入商品) AS 順位"
strSQL = strSQL & " From T_DATA"
Call RUN_SQL(strSQL) 'SQLの発行確認
%>
<h2>Select文を重ね、強引にフィールドを作成する</h2>
顧客・商品単位の順位が付いたので、<br>
強引に、顧客,商品0,商品1,商品2の表を作ってみます。<br>
Select文の埋め込み(サブクエリー)を使って、フィールドを作成してます。<br>
かなり長いけど<br>
<pre>SELECT
T_MOTO.顧客,
( SELECT T_000.購入商品 FROM T_DATA AS T_000
WHERE ( (T_MOTO.顧客=T_000.顧客)
AND ( (Select Count(*) From T_DATA AS T_TEMP
Where T_TEMP.顧客 = T_000.顧客
And T_TEMP.購入商品 < T_000.購入商品))=0);
) AS 商品0,
( SELECT T_000.購入商品 FROM T_DATA AS T_000
WHERE ( (T_MOTO.顧客=T_000.顧客)
AND ( (Select Count(*) From T_DATA AS T_TEMP
Where T_TEMP.顧客 = T_000.顧客
And T_TEMP.購入商品 < T_000.購入商品))=1);
) AS 商品1,
( SELECT T_000.購入商品 FROM T_DATA AS T_000
WHERE ( (T_MOTO.顧客=T_000.顧客)
AND ( (Select Count(*) From T_DATA AS T_TEMP
Where T_TEMP.顧客 = T_000.顧客
And T_TEMP.購入商品 < T_000.購入商品))=2);
) AS 商品2
FROM T_DATA AS T_MOTO; </pre>
※あまりお奨めできないけど、Select文の中にさらに条件を埋め込んでます・・・<br>
<%
'
strSQL = "Select "
strSQL = strSQL & " T_MOTO.顧客, "
'順位が0のデータを強引に持ってくる
strSQL = strSQL & " ( SELECT T_000.購入商品 FROM T_DATA AS T_000"
strSQL = strSQL & " WHERE ((T_MOTO.顧客=T_000.顧客)"
strSQL = strSQL & " AND ((Select Count(*) From T_DATA AS T_TEMP"
strSQL = strSQL & " Where T_TEMP.顧客 = T_000.顧客"
strSQL = strSQL & " And T_TEMP.購入商品 < T_000.購入商品))=0);"
strSQL = strSQL & " ) AS 商品0, "
'順位が1のデータを強引に持ってくる
strSQL = strSQL & " ( SELECT T_000.購入商品 FROM T_DATA AS T_000"
strSQL = strSQL & " WHERE ((T_MOTO.顧客=T_000.顧客)"
strSQL = strSQL & " AND ((Select Count(*) From T_DATA AS T_TEMP"
strSQL = strSQL & " Where T_TEMP.顧客 = T_000.顧客"
strSQL = strSQL & " And T_TEMP.購入商品 < T_000.購入商品))=1);"
strSQL = strSQL & " ) AS 商品1, "
'順位が2のデータを強引に持ってくる
strSQL = strSQL & " ( SELECT T_000.購入商品 FROM T_DATA AS T_000"
strSQL = strSQL & " WHERE ((T_MOTO.顧客=T_000.顧客)"
strSQL = strSQL & " AND ((Select Count(*) From T_DATA AS T_TEMP"
strSQL = strSQL & " Where T_TEMP.顧客 = T_000.顧客"
strSQL = strSQL & " And T_TEMP.購入商品 < T_000.購入商品))=2);"
strSQL = strSQL & " ) AS 商品2 "
strSQL = strSQL & " FROM T_DATA AS T_MOTO;"
Call RUN_SQL(strSQL) '
%>
<h2>さらにグループ化した</h2>
データが重複しているので、顧客でグループ化して結果を整えました。<br>
Group By 顧客を最後に追加してやっとOKかな・・・<br>
<%
strSQL = "Select "
strSQL = strSQL & " T_MOTO.顧客, "
'順位が0のデータを強引に持ってくる
strSQL = strSQL & " ( SELECT T_000.購入商品 FROM T_DATA AS T_000"
strSQL = strSQL & " WHERE ((T_MOTO.顧客=T_000.顧客)"
strSQL = strSQL & " AND ((Select Count(*) From T_DATA AS T_TEMP"
strSQL = strSQL & " Where T_TEMP.顧客 = T_000.顧客"
strSQL = strSQL & " And T_TEMP.購入商品 < T_000.購入商品))=0);"
strSQL = strSQL & " ) AS 商品0, "
'順位が1のデータを強引に持ってくる
strSQL = strSQL & " ( SELECT T_000.購入商品 FROM T_DATA AS T_000"
strSQL = strSQL & " WHERE ((T_MOTO.顧客=T_000.顧客)"
strSQL = strSQL & " AND ((Select Count(*) From T_DATA AS T_TEMP"
strSQL = strSQL & " Where T_TEMP.顧客 = T_000.顧客"
strSQL = strSQL & " And T_TEMP.購入商品 < T_000.購入商品))=1);"
strSQL = strSQL & " ) AS 商品1, "
'順位が2のデータを強引に持ってくる
strSQL = strSQL & " ( SELECT T_000.購入商品 FROM T_DATA AS T_000"
strSQL = strSQL & " WHERE ((T_MOTO.顧客=T_000.顧客)"
strSQL = strSQL & " AND ((Select Count(*) From T_DATA AS T_TEMP"
strSQL = strSQL & " Where T_TEMP.顧客 = T_000.顧客"
strSQL = strSQL & " And T_TEMP.購入商品 < T_000.購入商品))=2);"
strSQL = strSQL & " ) AS 商品2 "
strSQL = strSQL & " FROM T_DATA AS T_MOTO "
strSQL = strSQL & " Group By 顧客; "
Call RUN_SQL(strSQL) '
%>
<hr>
↑なんとか顧客別に横に商品名を出せたのかなぁ・・でもなぁ<br>
ここまでするなら、1レコード単位で回して、自分でやったほうがいいような・・<br>
</body>
</html>
<%
'SQL文を受け取り、DBに対してSQLを発行、データを表示するテスト関数
Sub RUN_SQL(strSQL)
'ADO DB Connection オブジェクトを作成する、英文そのままじゃん
Set db=Server.CreateObject("ADODB.Connection")
'データアクセスにはJet.OLEDB.4.0を使うことを設定
db.Provider = "Microsoft.Jet.OLEDB.4.0"
'次に、接続DBの位置を渡すので、Server.MapPathで変換して渡す
db.ConnectionString = Server.MapPath("db105.mdb")
db.open 'データベースを開く
Response.Write "発行するSQL文<br>"
Response.Write Server.HTMLEncode(strSQL) & "<BR>"
Set rs = db.Execute(strSQL)
'データの表示をテーブルで行う
Response.Write "<TABLE Border='1'>"
'見出しを(フィールド名を)そのまま書き込む
Response.Write "<TR>"
For Each fld_A In Rs.Fields 'フィールドのアイテムに対してループ
Response.Write "<TH>" & fld_A.Name & "</TH>"
'↑.Nameでフィールド名を表示する
Next
Response.Write "</TR>"
'お約束のEOFまでループは(データが無くなるまでループ)、
Do While rs.EOF = False 'レコードセットの.EOFがFalseの間
Response.Write "<TR>" '内容を表示する
For Each fld_A In Rs.Fields 'フィールドのアイテムに対してループ
Response.Write "<TD>" & fld_A.Value & "</TD>"
'↑.Valueでフィールドの値を表示する
Next
Response.Write "</TR>"
'次のレコードにポインタを移動する
rs.MoveNext 'これを忘れると悲惨なことに、、、
Loop
Response.Write "</TABLE>" 'テーブルは終わりです
'後始末
rs.Close '開いていたレコードセットを閉じる
db.Close 'データベースも閉じようよ
Set db = Nothing 'お行儀よくオブジェクトも開放しましょう
End Sub
%>
|
|