三流君ASPで遊ぶ、失敗する

[三流君] Top ken3.orgへ
[ASP解説] ASPの解説TOP
[ASP記事 バックナンバー] 番号順のバックナンバー
[SOHO/在宅プログラマー/派遣] 派遣のお話ほか
[...サイトマップ(総合案内へ)]




分類別ガイド
ADOで[ADO Mdb接続] ,[ADO Excel接続] ,[ADO CSV接続]

[ASP Form データのやりとりPOSTとGET]
[ASPでTextFile操作]
[ASPでVBScriptを使う]
[その他サンプル]

バックナンバー No.85 〜 No.89


No.85 2003/11/11
ADOでExcel(*.xls)に接続 .GetRowsで全件読み込んでみた
[ページTOPへ戻る]

<ADOでExcel(*.xls)に接続 .GetRowsで全件読み込んでみた>

こんにちは、三流プログラマーのKen3です。 前回のASP ADO Excel読み込みの続きで、 .GetRowsメソッドで少し遊べそうだったので、連続発行します。

/* * 1.今回のキッカケ */

掲示板で下記の質問をもらいました ------ ><ADOでExcelファイル(*.xls)とやっと接続できた(ほっ)>のページ、とって >も役に立ちました! >サーバーにエクセルが入ってないのに、一生懸命 >Set xlApp = Server.CreateObject("Excel.Application") >でつなごうとしてました(^^*) > >で、すみません、初歩的なことを教えてください・・・ >Set xlApp = Server.CreateObject("Excel.Application")では、セルの値を参照 >する時に、 ><% Response.Write xlSht.Range("b3").Value %> >でよかったのですが、このように、ADOを使う場合はどういう指定になるんで >しょうか。。 > >ACCESSのDBなら、 ><%= rs.Fields("test").Value %>ですよね。 ------ と、 b3のセルへのアクセス方法について、質問をもらいました。 に対して、前回解答したのが、 http://www.ken3.org/cgi-bin/test/test084-1.asp で、 Con = "Driver={Microsoft Excel Driver (*.xls)};DBQ=" & _ Server.MapPath("test084.xls") & ";" strSQL = "select * from [Sheet1$]" Rs.Open strSQL, Con, 0 とExcel接続、シート指定でレコードセットを作成して、 列名無しで接続できるが、先頭行が強引にフィールド名となってしまう。 B3のセルに対して、アクセスするには、 先頭行(A1やB1,C1,D1)がフィールド名となっているので、 Open時のカーソルは、A2,B2,C2と2行目からのスタートなので、 3行目に行くために、.MoveNextで1行空読みして、 Response.Write "Rs.MoveNext<br>" Rs.MoveNext '1行飛ばす Response.Write "Rs.Fields(1)は<big>[" & Rs.Fields(1) & "]</big>です<br>" なんて感じで逃げてました。 なんかなぁ・・・イマイチ(笑)と思いつつ、イロイロと探ってました。

/* * 2.ADO .GetRows を発見 */

http://www.ken3.org/cgi-bin/group/asp_ado_excel.asp に ADO Excel接続関係の情報をまとめてます。 ADOでMDBを使いSQLを発行して遊んでいるサンプルは、 http://www.ken3.org/cgi-bin/group/asp_ado_mdb.asp にまとめてます。 と 宣伝を入れつつ、 いろいろとWeb上で探していたら、 ADOで .GetRows を使用して、 ~~~~~~~~~~~~~~ MDBからデータを一気にメモリに展開しているサンプルを見かけた。 おっ、 ADOは接続が違うだけで、共通で使えると聞いたような、さっそく使ってみました。

/* * 3.サンプルを作ってみた(行列の違いでハマった) */

読み込むテストデータは下記のような感じです。 A列 B列 C列 D列 1: 列の項目名がなかったら? 2: c2どうなるの? 3: b3のセルはここ 4: a4のせるはここ 5: d5に1つ端っこ 6: 名前 三流君 7: 住所 東京都の田舎町 8: 好きな球団 横浜ベイスターズ 9: 10: 名前範囲も付けてません END? ※シート名はデフォルトのよくみかける[Sheet1]に作りました、  ブック名はtest084.xlsで、aspと同じディレクトリにFTPでUPしてあります ↑が作成した表のイメージです。 このtest084.xlsに対して、接続文字を作成して、 シートをテーブル代わりにしてADOでアクセスします。 '接続文字 Con = "Driver={Microsoft Excel Driver (*.xls)};DBQ=" & _ Server.MapPath("test084.xls") & ";" 'SQL文 Sheet1$として、シートのみ指定してみます strSQL = "select * from [Sheet1$]" '接続文字列、SQLを渡して、レコードセットを開く Rs.Open strSQL, Con, 0 '0=adOpenForwardOnly ここまでは、前回のコピー、 で、やっと 今回説明したい.GetRowsの登場 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 'rs.GetRowsで読み込む dataBOX = Rs.GetRows() 'レコードセットを配列にする あれれ、たった1行? こんな感じで、Rs.GetRows()とすると、 2次元配列でレコードセットの内容を作成してくれます。 あとは、テストで表示してみました。 Response.Write "dataBOX(3,5)=[" & dataBOX(3,5) & "].." あれ?エラーだよ Microsoft VBScript 実行時エラー エラー '800a0009' インデックスが有効範囲にありません。: '[number: 5]' /cgi-bin/test/test085-1.asp, 行 58 なんで? 実は、返された配列のdataBOXの中身は、 変数(列,行)の並びだったんですね。 ~~~~~~~~~~~ ExcelのCells(行,列)と見事に間違えてしまいました。 あと、先頭行は、やはり項目名として使われているので注意が必要です。 それと、 えっ、まだあるの? 配列が0番目から始まるので、やはりExcelのCells(行,列)は1からと混同しないでね。 あとは、まだあるの?えっと(オイオイ) あっ、当たり前の話だけど、全件メモリ上の配列に読み込むので 件数などが少ないデータで使ってね(考えて使ってね) ※件数少なければ、.GetRowsで一気に読むのもありかなぁ。 http://www.ken3.org/cgi-bin/test/test085-1.asp で、テストできます。 ※実行して、Cells(行,列)との違いを見てください。 ソースは、下記のような感じです(test085-1.asp) <%@LANGUAGE=VBScript%> <html> <head> <title>ADOでExcel(*.xls)に接続 .GetRowsで全件読み込んでみた</title> </head> <body> <h1>ADOでExcel(*.xls)に接続 .GetRowsで全件読み込んでみた</h1> test085-1.asp<br> ASPからADOを使用してExcel(*.xls)に接続して、<br> [Sheet1$]でシートにアクセスして、レコードセットを作成後、<br> <strong>rs.GetRows</strong>でレコードセットから配列を作成する<br> <br> <hr> <% 'ADO DB Recordset オブジェクトを作成する、英文そのままじゃん Set rs=Server.CreateObject("ADODB.Recordset") '接続文字 Con = "Driver={Microsoft Excel Driver (*.xls)};DBQ=" & _ Server.MapPath("test084.xls") & ";" Response.Write "作った、使った接続文字列は<br>" Response.Write "<CODE>Con = <b>" & Con & "</b></CODE><hr>" 'SQL文 Sheet1$として、シートのみ指定してみます strSQL = "select * from [Sheet1$]" Response.Write "作った、使ったSQL文字列は<br>" Response.Write "<CODE>strSQL = <b>" & strSQL & "</b></CODE><hr>" '接続文字列、SQLを渡して、レコードセットを開く Rs.Open strSQL, Con, 0 '0=adOpenForwardOnly Response.Write "<CODE>Rs.Open strSQL, Con, 0</CODE>" Response.Write "で、レコードセットを作成しました<hr>" 'rs.GetRowsで読み込む dataBOX = Rs.GetRows() 'レコードセットを配列にする Response.Write "<CODE>dataBOX = <b>rs.GetRows</b></CODE>" Response.Write "で、レコードセットを配列イメージで読み込む<hr>" Response.Write "配列のイメージを表示する<br>" Response.Write "dataBOX(3,0)=[" & dataBOX(2,0) & "]<br>" Response.Write "dataBOX(1,1)=[" & dataBOX(1,1) & "]<br>" Response.Write "dataBOX(0,2)=[" & dataBOX(0,2) & "]<br>" Response.Write "dataBOX(0,4)=[" & dataBOX(0,4) & "].." Response.Write "dataBOX(1,4)=[" & dataBOX(1,4) & "]<br>" Response.Write "dataBOX(0,5)=[" & dataBOX(0,5) & "].." Response.Write "dataBOX(1,5)=[" & dataBOX(1,5) & "]<br>" Response.Write "dataBOX(0,6)=[" & dataBOX(0,6) & "].." Response.Write "dataBOX(1,6)=[" & dataBOX(1,6) & "]<br>" Response.Write "dataBOX(0,8)=[" & dataBOX(0,8) & "].." Response.Write "dataBOX(3,8)=[" & dataBOX(3,8) & "]<br>" Rs.Close %> こんな感じで、<b>.GetRows</b>で配列に取り込み使用可能<br> </font> <hr> </body> </html> う〜ん、なかなかB3とわかりやすくアクセスする方法って、なさそう・・・・ -【けんぞう!】--------------------------------------------------------- ASPが利用可能なレンタルサーバーをお探しのアナタ、 http://www.ken3.org/asp/server.html ← けんぞうも使っているサーバーの紹介 『おっIISでbasp21でメール送信、mdbも使えるよ』(三流PG:31歳) ------------------------------------------------------------------------ 

/* * 4.終わりの挨拶 </HTML> */

今回は、 ASPでADOを使用して*.xlsと接続して、 .GetRowsで全件メモリ上の配列に取り込んでみました。 なんか、まだ、サクっとxxxx!B3みたいに出来なかったけど、 参考になったかなぁ・・・・ いろいろと問題点を残しつつ、脱線・寄り道の多いメルマガですが、 今後とも、よろしくお願いします。 何かの参考となれば幸いです。 ASP、VBScript勉強中の三流プログラマーのKen3でした。

No.86 2003/11/16
Ubound(配列,1)とUbound(配列,2)で遊ぶ
[ページTOPへ戻る]

<Ubound(配列,1)とUbound(配列,2)で遊ぶ>

こんにちは、三流プログラマーのKen3です。 前回のASP ADO .GetRowsメソッドで少し遊んでました。 そこで、(列,行)だとか(行,列)とか騒いでました。

/* * 1.今回のキッカケ */

前回、下記のイメージのExcelテストデータを読み込む処理で、 .GetRowsを使用しました。 A列 B列 C列 D列 1: 列の項目名がなかったら? 2: c2どうなるの? 3: b3のセルはここ 4: a4のせるはここ 5: d5に1つ端っこ 6: 名前 三流君 7: 住所 東京都の田舎町 8: 好きな球団 横浜ベイスターズ 9: 10: 名前範囲も付けてません END? ※シート名はデフォルトのよくみかける[Sheet1]に作りました、  ブック名はtest084.xlsで、aspと同じディレクトリにFTPでUPしてあります ↑が作成した表のイメージです。 このtest084.xlsに対して、接続文字を作成して、 シートをテーブル代わりにしてADOでアクセスしました。 '接続文字 Con = "Driver={Microsoft Excel Driver (*.xls)};DBQ=" & _ Server.MapPath("test084.xls") & ";" 'SQL文 Sheet1$として、シートのみ指定してみます strSQL = "select * from [Sheet1$]" '接続文字列、SQLを渡して、レコードセットを開く Rs.Open strSQL, Con, 0 '0=adOpenForwardOnly 'rs.GetRowsで読み込む dataBOX = Rs.GetRows() 'レコードセットを配列にする こんな感じで、Rs.GetRows()とすると、 2次元配列でレコードセットの内容をdataBOXに作成してくれます。 ここまでは、よかったけど、 Response.Write "dataBOX(3,5)=[" & dataBOX(3,5) & "].." なんてテストすると、エラーだよ(笑) Microsoft VBScript 実行時エラー エラー '800a0009' インデックスが有効範囲にありません。: '[number: 5]' /cgi-bin/test/test085-1.asp, 行 58 なんで? なんてことで、ハマってました(オイオイ) 原因は、返された配列のdataBOXの中身は、 変数(列,行)の並びだったんですね。 ~~~~~~~~~~~ ExcelのCells(行,列)と見事に間違えてしまいました。 あと、先頭行は、やはり項目名として使われているので注意が必要です。 それと、 えっ、まだあるの? 配列が0番目から始まるので、やはりExcelのCells(行,列)は1からと混同しないでね。 http://www.ken3.org/cgi-bin/test/test085-1.asp が、前回作成したサンプルです。 ※実行して、Cells(行,列)との違いを見てください。

/* * 2.本当の原因 */

dataBOX = Rs.GetRows() 'レコードセットを配列にする の 戻り値が、(列,行)の配列で、 ExcelのCellsの(行,列)と勘違いしたなんて書いているが、 本当の原因は別のところにあった。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ いつもの自己分析・右脳左脳の小話だと、 ※勘違いした・勘違いした ※行,列じゃなくて列,行だった なんて、アンタ騒いでいるけど、 そんなアホなエラーが発生するのって、 アンタがプログラマーの生活習慣病にかかっているからだろ? プログラマーの生活習慣病?って何? テスクワークの肥満? それもありがちだけど、そうじゃなくて、 普段のプログラムの組み方が、固定で・・って処理が多いんだよ。 フィールドは半永久的に変わらない や データは固定でn個 とか、決め付けてプログラム組んでる、 そんな習慣病に陥ってない? 普段から偏ったプログラム組んでると、ダメだよ。

/* * 3.配列の要素を知るには */

配列の要素数を知るには? Split関数で分割された配列に対して、 UBound関数で要素数を調べて、表示、 http://www.ken3.org/cgi-bin/test/test024-2.asp が、そんなサンプルでした。 strBOX = Split(strMOTO, " ") とSplit関数で文字列から配列を作成後、 'ループでデータを表示させる For i = 0 To UBound(strBOX) 'UBound使用インデックス最大値までループ とUBound関数で配列の要素数を判断、ループさせてます。 普段から、UBound関数を使っていれば(プログラマーの食生活がよければ) こんなことにならなかったのにね。 UBound関数っていい食品も取るようにしますか。 農薬まみれの固定処理はやめて・・・ んっ?チョット待てよ、今回調べたいのって2次元配列ですよ? 2次元配列の要素数ってわかるの? だから、マニュアル読めよ。 ちぇ、適当に食材入れないで、レシピ集をたまには見るか。 Ubound(配列,1)とUbound(配列,2)なんて書き方できるみたいです。 Dim BOX(12,5) と宣言して、 Ubound(BOX, 1)とUbound(BOX, 2)でテストしてみました Ubound(BOX, 1)が12 Ubound(BOX, 2)が5 をそれぞれ返します。 こんな感じで、Ubound関数を使用可能です http://www.ken3.org/cgi-bin/test/test086-1.asp で、テストできます。

/* * 4..GetRowsと組み合わせて使ってみた */

dataBOX = Rs.GetRows() で読み込んだレコードに対して、 For y = 0 To Ubound(dataBOX, 2) For x = 0 To Ubound(dataBOX, 1) でループを作り、表示してみました。 http://www.ken3.org/cgi-bin/test/test086-2.asp でテスト可能です。 <%@LANGUAGE=VBScript%> <html> <head> <title>ADO .GetRowsで全件読み込み、Uboundで行列チェック</title> </head> <body> <h1>.GetRowsで全件読み込み、Uboundで行列チェック</h1> test086-2.asp<br> ASPからADOを使用してExcel(*.xls)に接続して、<br> [Sheet1$]でシートにアクセスして、レコードセットを作成後、<br> <strong>rs.GetRows</strong>でレコードセットから配列を作成する<br> [<a Href="test084.xls" TARGET="_blank">test084.xls</a>]←がファイルです<br> <br> <hr> 読み込んだ配列に対して、Ubound関数で、行列の最大値を調べて<br> データを表示してみました。<br> <hr> <% 'ADO DB Recordset オブジェクトを作成する、英文そのままじゃん Set rs=Server.CreateObject("ADODB.Recordset") '接続文字 Con = "Driver={Microsoft Excel Driver (*.xls)};DBQ=" & _ Server.MapPath("test084.xls") & ";" Response.Write "作った、使った接続文字列は<br>" Response.Write "<CODE>Con = <b>" & Con & "</b></CODE><hr>" 'SQL文 Sheet1$として、シートのみ指定してみます strSQL = "select * from [Sheet1$]" Response.Write "作った、使ったSQL文字列は<br>" Response.Write "<CODE>strSQL = <b>" & strSQL & "</b></CODE><hr>" '接続文字列、SQLを渡して、レコードセットを開く Rs.Open strSQL, Con, 0 '0=adOpenForwardOnly Response.Write "<CODE>Rs.Open strSQL, Con, 0</CODE>" Response.Write "で、レコードセットを作成しました<hr>" 'rs.GetRowsで読み込む dataBOX = Rs.GetRows() 'レコードセットを配列にする Response.Write "<CODE>dataBOX = <b>rs.GetRows</b></CODE>" Response.Write "で、レコードセットを配列イメージで読み込む<hr>" Response.Write "配列のイメージを表示する<br>" Dim y, x Response.Write "<Table border=1>" 'テーブルで表示 For y = 0 To Ubound(dataBOX, 2) Response.Write "<TR>" '行の開始 For x = 0 To Ubound(dataBOX, 1) Response.Write "<TD>" & dataBOX(x, y) & "<TD>" Next Response.Write "</TR>" '行の終わり Next Response.Write "</Table>" 'テーブルの終了 Rs.Close %> こんな感じで、<b>.GetRows</b>で配列に取り込みUboundで個数を調べることが可能です<br> ※あと、先頭行は、やはり項目名として使われているので注意が必要ですが。<br> </body> </html> -【けんぞう!】--------------------------------------------------------- ASPが利用可能なレンタルサーバーをお探しのアナタ、 http://www.ken3.org/asp/server.html ← けんぞうも使っているサーバーの紹介 『おっIISでbasp21でメール送信、mdbも使えるよ』(三流PG:31歳) ------------------------------------------------------------------------ 

/* * 5.終わりの挨拶 </HTML> */

今回は、 私の生活習慣病(固定プログラム病) を改善するために、 Ubound(配列,1)とUbound(配列,2)なんて使ってみました。 いろいろと問題点を残しつつ、脱線・寄り道の多いメルマガですが、 今後とも、よろしくお願いします。 みなさんは、バランスよく関数使って(偏った関数使わないで汎用的にね) 環境やデータによって、バグの発生しない健康なプログラムを作ってね。 何かの参考となれば幸いです。 ASP、VBScript勉強中の三流プログラマーのKen3でした。

No.87 2003/11/17
ADO SQL Like演算子で部分検索する
[ページTOPへ戻る]

<ADO SQL Like演算子で部分検索する>

こんにちは、三流プログラマーのKen3です。 今回は、Like演算子で部分検索を行ってみます

/* * 1.今回のキッカケ */

掲示板 http://www.ken3.org/cgi-bin/bbs/asp/wforum.cgi でもらった質問、処理していないのがあるので、 1つ1つやらないとなぁと思いつつ・・・

/* * 2.Like演算子を使用した検索 */

SQL Select Where文で、検索したりしてました。 Select * From KANSOU WHERE F_KUBUN = 'ASP' ORDER BY WriteTime DESC http://www.ken3.org/cgi-bin/test/test030-1.asp?KUBUN=ASP と F_KUBUN フィールドが'ASP'のデータをセレクトしたり Select * From KANSOU Where F_KUBUN = 'ASP' OR F_KUBUN = 'VBA' ORDER BY WriteTime DESC http://www.ken3.org/cgi-bin/test/test046-1.asp?ASP=on&VBA=on や Select * From KANSOU WHERE F_KUBUN IN ('ASP', 'VBA') ORDER BY WriteTime DESC http://www.ken3.org/cgi-bin/test/test046-3.asp?KUBUN=ASP&KUBUN=VBA で、 F_KUBUNが'ASP'か'VBA'のデータをセレクトしたり。 > 10 で10より上, < 20 で20より下と数値も普通に使えたりします。 あとは、部分的にデータが一致したら、検索したい、そんな要望もあると思います。 例えば、 http://www.ken3.org/cgi-bin/test/test083-1.asp で Select TOP 20 URL, Count(URL) As URLCNT From log GROUP BY URL   ORDER BY Count(URL) DESC とSQL文を発行して、TOP20の合計値を出力しています。 No. URL 訪問者件数 1 /etc/ranking/auto_04.html 639人 2 /etc/500yen/ebank.html 591人 3 /etc/ranking/hobby_07.html 478人 ・ ・ ・ ・   ・ ・ 18 /etc/pc.html 206人 19 /etc/ranking/media_07.html 199人 20 /etc/ranking/hobby_06.html 189人 これだと、全てのデータのランキングです。 これを、hobby_XXだけを出力したい、そんな時があると思います。 そんな時に便利なのが、 Like 演算子です。 Where フィールド Like '%hobby%' と 指定すると、フィールドにhobbyが含まれているデータを取得してくれます。 http://www.ken3.org/cgi-bin/test/test087-1.asp?q=drink と q=XXXXみたいにURLに載せたパラメータを取得して、 SQL文を作成してみたいと思います。

/* * 3.作成したサンプル */

えっと、まずは、 http://www.ken3.org/cgi-bin/test/test087-1.asp?q=pc みたいに、q=の値を受け取らないとなぁ。 SQL文の作成時に、 Request.QueryString("q") の値があるか、チェックして、存在したときにLike演算子を使用します。 ※強引に受け取ったパラメータに%を追加してます。 'TOP20を指定 Where URL LIKE '%XXX%'で条件を指定する strSQL = "Select TOP 20 URL, Count(URL) As URLCNT " strSQL = strSQL & "From log " 'パラメータをチェックする(test087-1.asp?q=xxxxxでもらう) qqq = Trim(Request.QueryString("q")) '両端のスペースを除いて受け取る If qqq <> "" Then 'データありの時、Like演算子の条件を追加する strSQL = strSQL & "Where URL Like '%" & qqq & "%' " Response.Write "条件[" & qqq & "]を受け取りました<br>" Else Response.Write "q=のパラメータが無かったよ(笑)<br>" 'データ無しの時 End If strSQL = strSQL & "GROUP BY URL " strSQL = strSQL & "ORDER BY Count(URL) DESC" こんな感じで、SQL文を作成して、発行してます。 あとは、再検索用に、 <FORM ACTION="test087-1.asp" METHOD="GET"> 絞り込む検索条件を入れて、再検索ボタンを押してください。<br> 検索条件:<INPUT TYPE="TEXT" NAME="q" VALUE="<%=qqq%>"> <INPUT TYPE="submit" VALUE="再検索"><br> ※例)pc auto drink 500yenなどなど、URLの一部を入力<br> </FORM> と METHOD="GET"でフォームを作成して、 <INPUT TYPE="TEXT" NAME="q" VALUE="<%=qqq%>"> で条件を入力させ、 ACTION="test087-1.asp"の指定で、自分自身を再度コールしてます。 http://www.ken3.org/cgi-bin/test/test087-1.asp?q=old http://www.ken3.org/cgi-bin/test/test087-1.asp?q=500yen http://www.ken3.org/cgi-bin/test/test087-1.asp?q=fashion などで下記のプログラムのテストが出来ます。 test087-1.asp <%@LANGUAGE=VBScript%> <html> <head> <title>SQL SELECT WHERE句で Like演算子を使用して部分検索する</title> </head> <body> <!-- Ken3 --><!-- #include file="info.inc" --> <h1>SQL SELECT WHERE句で Like演算子を使用して部分検索する</h1> test087-1.asp<br> <hr> cnt_etc.mdb から訪問されたURLをグループ化して集計、降順に表示<br> <strong>Like演算子</strong>でデータを絞り込んでみました。<br> Select TOP 20 URL, Count(URL) As URLCNT 〜<br> <font color="red">Where URL <strong>Like</strong> '%XXXX%'<br> と受け取ったq=を設定してみます</font><br> <% 'ADO DB Connection オブジェクトを作成する、英文そのままじゃん Set db=Server.CreateObject("ADODB.Connection") '.Provider?プロバイダー?通信会社?じゃなくって 'データアクセスにはJet.OLEDB.4.0を使うことを設定 db.Provider = "Microsoft.Jet.OLEDB.4.0" '次に、接続DBの位置を渡すので、Server.MapPathで変換して渡す db.ConnectionString = Server.MapPath("cnt_etc.mdb") 'やっとデータベースを開ける db.open 'お約束のレコードセットの作成 'GROUP BY句 で グループ化 Count関数で集計 ORDER BY句で並べ替え 'TOP20を指定 Where URL LIKE '%XXX%'で条件を指定する strSQL = "Select TOP 20 URL, Count(URL) As URLCNT " strSQL = strSQL & "From log " 'パラメータをチェックする(test087-1.asp?q=xxxxxでもらう) qqq = Trim(Request.QueryString("q")) '両端のスペースを除いて受け取る If qqq <> "" Then 'データありの時、Like演算子の条件を追加する strSQL = strSQL & "Where URL Like '%" & qqq & "%' " Response.Write "条件[" & qqq & "]を受け取りました<br>" Else Response.Write "q=のパラメータが無かったよ(笑)<br>" 'データ無しの時 End If strSQL = strSQL & "GROUP BY URL " strSQL = strSQL & "ORDER BY Count(URL) DESC" 'オマケで画面にデータ表示 Response.Write "<hr>発行する(した)SQL文は<br><B><font color='green'>" Response.Write strSQL & "</font></B><br>です<hr>" Set rs = db.Execute(strSQL) 'データの表示をテーブルで行う Response.Write "<TABLE Border='1'>" '見出しをバカっぽく、そのまま書き込む Response.Write "<TR>" Response.Write "<TD>No.</TD>" Response.Write "<TD>URL</TD>" Response.Write "<TD>訪問者件数</TD>" Response.Write "</TR>" 'EOFまでループ nCNT = 1 Do While rs.EOF = False '.EOFがFalseの間 Response.Write "<TR>" '内容を表示する Response.Write "<TD>" & nCNT & "</TD>" Response.Write "<TD><A HREF='" & rs.Fields.Item("URL") & "' Target='_top'>" Response.Write rs.Fields.Item("URL") & "</A></TD>" Response.Write "<TD ALIGN=RIGHT>" & rs.Fields.Item("URLCNT") & "人</TD>" Response.Write "</TR>" & Chr(13) & Chr(10) '次のレコードにポインタを移動する rs.MoveNext 'これを忘れると悲惨なことに、、、 'カウンタを増やす nCNT = nCNT + 1 Loop Response.Write "</TABLE>" 'テーブルは終わりです '開いていたレコードセットを閉じる rs.Close 'データベースも閉じようよ db.Close 'お行儀よくオブジェクトも開放しましょう(通常は自動的に解放されるけど) Set db = Nothing %> <hr> <FORM ACTION="test087-1.asp" METHOD="GET"> 絞り込む検索条件を入れて、再検索ボタンを押してください。<br> 検索条件:<INPUT TYPE="TEXT" NAME="q" VALUE="<%=qqq%>"> <INPUT TYPE="submit" VALUE="再検索"><br> ※例)pc auto drink 500yenなどなど、URLの一部を入力<br> </FORM> </body> </html>

/* * 4.Access97時代の*と間違えたことも在り */

お約束のネタだけど、 URL Like '*pc*' だと、ADOのSQLだとダメです。 けっこう、引っかかると思うので、%って感じで頭に入れて置いてください。 ※SQLの解析エンジンによって、違ったりするので、マニュアルみるかな・・・ http://www.microsoft.com/japan/developer/library/vdtsql/dvconusingwildcardcharacters.htm も参考にしてくださいね。 -【けんぞう!】--------------------------------------------------------- ASPが利用可能なレンタルサーバーをお探しのアナタ、 http://www.ken3.org/asp/server.html ← けんぞうも使っているサーバーの紹介 『おっIISでbasp21でメール送信、mdbも使えるよ』(三流PG:31歳) ------------------------------------------------------------------------ 

/* * 5.終わりの挨拶 </HTML> */

今回は、Like演算子を軽く書きました。 掲示板にあったのは、削除条件指定とページ送りでしょギク・・・ ハヤメにかたずけないと・・・ いろいろと問題点を残しつつ、脱線・寄り道の多いメルマガですが、 今後とも、よろしくお願いします。 何かの参考となれば幸いです。 ASP、VBScript勉強中の三流プログラマーのKen3でした。

No.88 2003/11/19
SQL HAVING句でSUMした値をチェックする
[ページTOPへ戻る]

<SQL HAVING句でSUMした値をチェックする>

こんにちは、三流プログラマーのKen3です。 レンタルサーバーもなんとか復旧したみたいです。 ※エラーの連絡あって、復旧の連絡無しかよ  と、読者からキツイ一言ももらいつつ、(オイオイ) 今回は、SQLのHAVING句で集計関数SUMの値をチェックしてみます。

/* * 1.今回のキッカケ */

掲示板 http://www.ken3.org/cgi-bin/bbs/asp/wforum.cgi で下記の質問をもらいました。 (メルマガ作者のジレンマ:心の中の右脳左脳バトル  質問の回答も先入れ先出しダロ、前の質問はクリアしたのかよ。  ※前の彼女との問題クリアしてないのに次に行くか?オイ・・・   簡単な問題に手をつけて、難しい問題は先送り・・それでいいの?   と心の中で思いつつ、発行してしまいました) ----- タイトル:数量0のときの項目削除 集計関数を使った表の作成で、例えば、数量が0の項目を表示しない ようにするには、どのようにSQLを書けば、いいのでしょうか? ----- に対して、 最近、勘違い回答が多い私は、 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ----- 投稿者名:Ken3(管理者) タイトル:Re: 数量0のときの項目削除 こんにちは。 現在0が表示されているSQL文 か 集計元の表を教えていただけると、 解答しやすいです、回答できるかもしれません。 (最近、私、勘違い回答多くって・・・) 普通にSum(XXX)で集計値が0のレコードなら、 Select URL, Count(URL) As URLCNT From log GROUP BY URL HAVING Count(URL) <> 0 ORDER BY Count(URL) DESC とか、HAVINGだけど、 Select SUM(AAA) AS F_A, SUM(BBB) AS F_B なんて感じで複数項目でフィールドを消すのか? それとも、クロス集計のクエリーで0項目をカットするのか? など、読みきれなかったので。 ---- と、自信の無い回答(笑)

/* * 2.集計値が0の行はSelectしない */

質問者から、下記の回答をもらう | 商品名 | 4月 | 5月 | 6月 | 7月 | 8月 | 9月 |上期計 | ---------------------------------------------------------------- | A1  | 1 |  2 | 3 |  4 | 5 |  6 |  21 | ---------------------------------------------------------------- | A2   | 0 |  0 | 0 |  0 | 0 | 0  |  0 | ---------------------------------------------------------------- | A3   | 3 |  1 | 5 |  6 | 7 |  8 | 30 | ---------------------------------------------------------------- | 小計 | 5 |  3 | 8 | 10 | 12 | 14 | 51 | ---------------------------------------------------------------- | B1  | 0 |  0 | 0 | 0 | 0 | 0 |  0  | ---------------------------------------------------------------- | B2 | 5 |  3 | 7 |  8 | 9 | 10 | 42 | ---------------------------------------------------------------- | B3   | 6 |  4 | 8 | 9 | 10 | 11 | 48 | ---------------------------------------------------------------- | 小計  | 11|  7 | 15 | 17 | 19 | 21 | 90 | ---------------------------------------------------------------- | 総計 | 16| 10 | 23 | 27 | 31 |35 | 141 | ---------------------------------------------------------------- ---- なるほどね、A2とB1は、0だから、表示したくない。 ※実際の表でもありがちなのが、10月から取引を始めた会社なんかは、  上期の表に0を出したくない。  また、残念だけど、8月で取引終了、下期の表には0で載せたくない。  そんな流れを勝手に想像。 ※取引先じゃなくて、夏物商品・冬物商品と期間限定商品あったら、  マスターにレコードあっても出したくない、そんな状況はありかなぁ。 んっ?どこかでみた表だなぁと思ったら、 http://www.ken3.org/cgi-bin/test/test076-2.asp で、 UNIONでつなげてた表でしたね。 Select T_月別売上.商品CD, T_商品.商品名, 売上4,売上5,売上6,売上7,売上8,売上9, ([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) AS 上期計 From T_月別売上, T_商品 Where T_月別売上.商品CD = T_商品.商品CD UNION ALL Select Left([T_月別売上.商品CD], 1) & 'ZZZZ' AS GroupCD , '小計' AS Dummy商品名 , Sum([売上4]) , Sum([売上5]) , Sum([売上6]) , Sum([売上7]) , Sum([売上8]) , Sum([売上9]) , Sum([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) AS 上期計 From T_月別売上, T_商品 Where T_月別売上.商品CD = T_商品.商品CD Group By Left([T_月別売上.商品CD], 1) & 'ZZZZ' Order By T_月別売上.商品CD と、明細の表と集計値をUNIONでつなげてました。 テストデータで B1の売上データ4月−9月を0にして明細を作成します。 B2は、4月−9月の売上アリで、Bの小計は表示させる あと、 グループDを追加して D1 コート D2 マフラー と冬物商品を作成して、4〜9月の売上無し、10月〜3月の下期に売上を作成。 上期の表には、グループ小計も出したくない、 そんな処理をやってみます。

/* * 3.Whereで0を排除する */

普通に発行したSQLを発行して、集計すると http://www.ken3.org/cgi-bin/test/test076-2.asp みたいに、レコードがあるのでSUMで集計して0のデータも表示されます。 ※テーブルの作り構造問題は別にして、考えてくださいね。 ↑0データが表示されている表イメージ さてと、上期の合計が0の場合、表示したくない。 そんな条件を入れてみますか。 条件? そうですね、条件を入れてみます。 だったらWhereに書くの? そうですね、Whereに条件を追加してみます(ANDで1つ増やします) 上期合計 > 0 と0以上の文を追加してみます。 普通に考えると、 Select T_月別売上.商品CD, T_商品.商品名, 売上4,売上5,売上6,売上7,売上8,売上9, ([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) AS 上期計 From T_月別売上, T_商品 Where T_月別売上.商品CD = T_商品.商品CD AND 上期計 > 0 ^^^^^^^^^^^^^^^^とANDにして、条件を追加します。 UNION ALL Select Left([T_月別売上.商品CD], 1) & 'ZZZZ' AS GroupCD , '小計' AS Dummy商品名 , Sum([売上4]) , Sum([売上5]) , Sum([売上6]) , Sum([売上7]) , Sum([売上8]) , Sum([売上9]) , Sum([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) AS 上期計 From T_月別売上, T_商品 Where T_月別売上.商品CD = T_商品.商品CD Group By Left([T_月別売上.商品CD], 1) & 'ZZZZ' Order By T_月別売上.商品CD こんな感じで、 ([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) AS 上期計 で、上期計の項目を作成しているので、 AND 上期計 > 0 と、上期が0以上なんて感じでOKと思いテストを行います。 すると、 Microsoft JET Database Engine エラー '80040e10' 1 つ以上の必要なパラメータの値が設定されていません。 /cgi-bin/test/test088-1.asp, 行 63 えっ、なんで? 追加したのって、AND 上期計 > 0なんだけど。 この 1 つ以上の必要なパラメータの値が設定されていません ってエラー、経験上、フィールド名が間違えている時に出てくる。 日本語のフィールド名だから? う〜ん、今後の調査メモに入れておいて、 AND ([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) > 0 と、書いてかわしました。 http://www.ken3.org/cgi-bin/test/test088-1.asp で、テスト実行すると、 上期0のデータ行は、表示されなくなりました。 が、 まだ、小計が0のDグループが表示されてます。 ↑0の明細は消えたが、0のD小計が表示されている表イメージ

/* * 4.SUMの集計値をHAVING句でチェック0データをハジク */

さてと、グループ集計の0も表示させたくないよね。 Select Left([T_月別売上.商品CD], 1) & 'ZZZZ' AS GroupCD , '小計' AS Dummy商品名 , Sum([売上4]) , Sum([売上5]) , Sum([売上6]) , Sum([売上7]) , Sum([売上8]) , Sum([売上9]) , Sum([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) AS 上期計 From T_月別売上, T_商品 Where T_月別売上.商品CD = T_商品.商品CD Group By Left([T_月別売上.商品CD], 1) & 'ZZZZ' に追加するとしたら、同じようにやると、 Select Left([T_月別売上.商品CD], 1) & 'ZZZZ' AS GroupCD , '小計' AS Dummy商品名 , Sum([売上4]) , Sum([売上5]) , Sum([売上6]) , Sum([売上7]) , Sum([売上8]) , Sum([売上9]) , Sum([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) AS 上期計 From T_月別売上, T_商品 Where T_月別売上.商品CD = T_商品.商品CD AND Sum([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) > 0 Group By Left([T_月別売上.商品CD], 1) & 'ZZZZ' と、 And Sum([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) > 0 の条件をWhereにANDで追加すればOKでしょ簡単簡単。 オイオイ本気かよ?やってみな。 言われなくてもやってみるよ、ほらできたでしょ? 表示されたよ、下記のエラーが Microsoft JET Database Engine エラー '80040e14' WHERE 句 (T_月別売上.商品CD=T_商品.商品CD And Sum([売上4]+[売上5]+[売上6] +[売上7]+[売上8]+[売上9])) で集計関数を使用することはできません。 /cgi-bin/test/test088-2.asp, 行 64 (エラー報告にムッと来つつ) えっ、なんでだよ。 だって、Where句って、フィールドに対しての条件だから、 Sumとか集計関数は使えないんだってばさ。 そうなんだぁ、わかってたら言ってよ。 三流プログラマーのクセに調子コイテルから、実際のエラー見たほうがいいんだよ。 集計結果を絞り込むには、HAVING句に条件を書くんですよ。了解した? HAVING句?と驚いたフリをしつつ(オイオイ) 下記のようなSQL文になります。 流れ的にGroup Byでグループ化された結果に対して出力条件を付けたいときに、 HAVING句を使用します。 Select Left([T_月別売上.商品CD], 1) & 'ZZZZ' AS GroupCD , '小計' AS Dummy商品名 , Sum([売上4]) , Sum([売上5]) , Sum([売上6]) , Sum([売上7]) , Sum([売上8]) , Sum([売上9]) , Sum([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) AS 上期計 From T_月別売上, T_商品 Where T_月別売上.商品CD = T_商品.商品CD Group By Left([T_月別売上.商品CD], 1) & 'ZZZZ' HAVING Sum([売上4]+[売上5]+[売上6]+[売上7]+[売上8]+[売上9]) > 0 ^^^^^^ なんて感じで、HAVING句を記述します。 http://www.ken3.org/cgi-bin/test/test088-2.asp でテストすると、やっと、目的の結果が得られると思います。 -【けんぞう!】--------------------------------------------------------- ASPが利用可能なレンタルサーバーをお探しのアナタ、 http://www.ken3.org/asp/server.html ← けんぞうも使っているサーバーの紹介 『おっIISでbasp21でメール送信、mdbも使えるよ』(三流PG:31歳) ------------------------------------------------------------------------ 

/* * 5.終わりの挨拶 </HTML> */

今回は、 Where句やHAVING句 で 0を取り除いた出力のSQLを軽く書きました。 いろいろと問題点を残しつつ、脱線・寄り道の多いメルマガですが、 今後とも、よろしくお願いします。 何かの参考となれば幸いです。 ASP、VBScript勉強中の三流プログラマーのKen3でした。

No.89 2003/12/21
SQL 集計関数MAXと副問い合わせ(サブクエリー)
[ページTOPへ戻る]

<SQL 集計関数MAXと副問い合わせ(サブクエリー)>

こんにちは、三流プログラマーのKen3です。 今回は、SQLの集計関数MAXと副問い合わせ(サブクエリー)を使ってみます。

/* * 1.今回のキッカケ */

掲示板 http://www.ken3.org/cgi-bin/bbs/asp/wforum.cgi で下記の質問をもらいました。 ----- タイトル:あまり初歩的ですいません ACCESS97のテーブル(下記)に「konyu」というテーブルがあり、 フィールド ID 数値型 とno 数値型があったとします。 IDの最大値のレコードのみ取得する場合 SQL ="SELECT * from kounyu where ID =(SELECT MAX(ID) from kounyu)"で取得出来るのですが、何故かnoの最大値のレコードを取 得できません。 SQL1 ="SELECT * from kounyu where no =(SELECT MAX(no) from kounyu)"ではダメ なのでしょうか? IDは1〜順番に付与され全レコードデータが入ってます noは後からinsert文で番号を入力するため、データが入ってたり 入ってなかったりします。 noのSQLを実行すると下記にエラーが表示されます。 「要求された名前、または序数に対応する項目がコレクションで見 つかりません。」 ----- ヤバイ・・・初歩的な問合せがわからないや・・・ 最近、初歩的と言われる問合せでハマッテマス・・・見かけ倒しの実力なので。

/* * 2.集計関数MAX */

SQLには、集計関数があって、SUM(項目名)だと、合計を計算してくれました。 あと、有名どころでは、MAX(項目名)で、最大値を返してくれます。 下記のテストデータを作成しました。 テーブル名:kounyu ID no 名前 金額 数量 1 100 Ken3 2000 5 2 20 けんぞう 100 200 3 250 あいうえお 1500 100 5 5 かきくけこ 55 55 6 10 さしすせそ 60 150 Select MAX(ID), MAX(no), MAX(金額), MAX(数量) From konyu と、SQL文を作成してみた。 'MAX関数を使用したSQL文を作成する strSQL = "Select MAX(ID), MAX(no), MAX(金額), MAX(数量) " strSQL = strSQL & " From kounyu " こんな感じで、文字列を作成して、 Set rs = db.Execute(strSQL) 'SQL発行、レコードセットの作成 で、レコードセットを作成してみました。 すると、結果は、 Expr1000 Expr1001 Expr1002 Expr1003 6 0 2000 200 んっ? 項目名が勝手に付いているのはまぁゆるすとして、 MAX(no)が0だよ・・・なぜ?250が返ってくれないとね。 ↑なぜかMAX(no)で0が返ってきた結果画面 なんか、noって名前が怪しいんだろうなぁと勝手な予想。 よく聞く話だと、予約語って感じかなぁ。 []で囲うと動く、そんな話も目にしてたので、SQL文を少し細工する。 'MAX関数を使用したSQL文を作成する strSQL = "Select MAX(ID), MAX([no]), MAX(金額), MAX(数量) " strSQL = strSQL & " From kounyu " と修正してみると、 http://www.ken3.org/cgi-bin/test/test089-1.asp で、テストすると、なんとかOKですね。 no等の予約語は、[]で囲うと正しくフィールドとして認識される。 ^^^^^^^^^^^^^^^^^^^^^^^^^^ 頭のスミに入れて置いてください。 --- 枠外解説・愚痴 --- フィールド名の頭に必ずF_と接頭語じゃないけど、付けて設計する先輩が居た。 そんな人達は、今回の[no]問題/予約語には、引っかからないのだろう。 コーディングミスを誘発しないテーブル設計ってのも必要ですね。

/* * 3.副問い合わせ(サブクエリー)を使い、最大値の行を表示してみる */

掲示板の質問で勉強した・・・なんて言っていると怒られるけど、 テーブル名:kounyu ID no 名前 金額 数量 1 100 Ken3 2000 5 2 20 けんぞう 100 200 3 250 あいうえお 1500 100 5 5 かきくけこ 55 55 6 10 さしすせそ 60 150 とデータがあった時に、 ・一番多く購入した人のデータ ・noが一番大きい人 を検索する場合 プログラムの組み方は、いろいろとあると思います。 データが少ないなら、全てのデータを頭から見ていき、 最大値のデータを代入する、そんな方法もありますが、 SELECT文の出力結果をもう一つのSELECT文のWhereの条件にする、 サブクエリーやクエリーの埋め込み、そんな方法をテストしてみます。 なんか変な日本語の説明でしたが、 Select 列名 From テーブル名  Where 列名 = (ここに条件として使いたいSQLをもう一つ書き込むことができます) ・一番多く購入した人のデータ を取り出すSQL文を下記のように作成することが出来ます。 '数量が一番大きい人を探すため、 'MAX関数を埋め込んだサブクエリー付のSQL文を作成する strSQL = "Select 名前 " strSQL = strSQL & " From kounyu " strSQL = strSQL & " Where 数量 = (Select MAX([数量]) From kounyu)" なんだぁ?こんなもん?って感じですが、 SQL文の幅が広がったと思います。 http://www.ken3.org/cgi-bin/test/test089-2.asp で、テストできます。 サブクエリー/SQL副問合せ、頭のスミにでも入れて置いてください。

/* * 4.終わりの挨拶 </HTML> */

今回は、 MAX関数を使った時、noのフィールド名は予約語なので[no]としてください。 サブクエリー/SQL副問合せを使ってみました。 いろいろと問題点を残しつつ、脱線・寄り道の多いメルマガですが、 今後とも、よろしくお願いします。 何かの参考となれば幸いです。 ASP、VBScript勉強中の三流プログラマーのKen3でした。



ページフッター リンクや広告、質問送信など

三流解説を読んでいただき、どうもです。ここから下は、三流君宛のメッセージ送信や 三流君のホームページの紹介・案内です
目的の情報が見つかったか?少々心配しつつ、、、※質問や感想は、気軽に送ってくださいね。

まぁ、基本はデータの受け取りかなぁ。
・[Form等を使用したデータのやり取り]・・・ASPと言っても、HTMLの入力フォームからデータを受け取ります。POSTやGETでやりとりを押さえますか。

次は、データの入出力 で ADOを使った(ADOで接続) と SQLの解説を少々
・[ADOでMdbファイルを使う]・・・MDBと接続して、簡単な追加・更新・削除を行った。
・[ADOでExcelと接続してみた]・・・.xlsと接続してSQLを使ってみた。
・[ADOでCSVと接続してみた]・・・.CSV テキストを読み出した。※更新・削除はできません

DBが使えるので、あまり使用しないけど、普通のテキストファイル処理
・[テキストファイル処理]・・・ファイルを開いて、書き込む。1行読み込みなどを軽く

VBScriptでFormat関数が無いなど、微妙にVBAと違うけど
[VBScript関数関係の説明]・・・少し、処理を書いてみた。
[その他処理サンプル]・・・あまり良いサンプル作れなかったけど。。。
何かの参考となれば幸いです。

ニガテな環境設定系など
[Win2003 Server に IIS を Setup]・・・ポイントの無い、ほぼ一本道解説だけど。
[IIS 仮想ディレクトの作成とASP動作TEST]・・・Web拡張でASPを有効にしただけです。

Blog:[三流君の作業日記]/ [サンプルコードのゴミ箱]/ 広告-[通販人気商品の足跡]

質問や要望など メッセージを送る(三流君に連絡する)

質問や要望など連絡方法でお互い確認が取りやすく、便利なのが掲示板なのですが、私の対応のまずさから不定期で荒れてしまい、掲示板は現在封鎖中です。(反省しなきゃ)
感想や質問・要望・苦情など 三流君へメッセージを送る。
時間的余裕のある要望・質問・苦情の場合は、下記のフォームからメッセージを送ることができます。

あなたのお名前(ニックネーム):さん
返信は?: 不用(HP更新を待つ) , E-mail→ アドレス:に返事をもらいたい



(感想や質問・要望 メッセージはHPで記事に載せることがあります。)


急ぎで連絡がほしい、そんな時は:[三流君連絡先アドレス]を見て連絡してください。



[三流君(TOP ken3.org へ戻る)] / [ASPで遊ぶ、失敗する] / [ASP記事 バックナンバー目次]