エクセル2003の初心者向けのVBA入門方法と自動発生SQL文の作成方法

このQ&Aのポイント
  • エクセル2003を使っている初心者の方がVBAを使用して自動発生SQL文を作成する方法について教えてください。
  • エクセル2003のシートに記入されたデータを元に、条件に従って自動的にSQL文を生成する方法を知りたいです。
  • 項目に○が付いているデータを元に、ユーザーごとに適切なSQL文を作成する方法について詳しく教えてください。
回答を見る
  • ベストアンサー

エクセル2003に詳しい方御教授願います。

    A    B    C    D    E    F    G    H    I 1            SA1   SA2  SB1  SB2   SC1  SC2  SC3 2  番号  名前 3  111   Xさん  ○         ○                  ○ 4  222   Yさん        ○                  ○ 上記のような情報がエクセルに記入されていたとします。 A2,B2,C1,D1,E1,F1,G1,H1,I1にそれぞれ項目名(列名)があるとします。 番号111と222の人がC1~I1までの項目に対して上記のように○が付いているとき 下記のようなSQL文(5行)をA5~A9に自動発生させることを実現したいです。 update tablename set type = SA1 where user = qqq111 ; update tablename set type = SB1 where user = aaa111 ; update tablename set type = SC3 where user = 111 ; update tablename set type = SA2 where user = qqq222 ; update tablename set type = SC2 where user = 222 ; 上記5文はそれぞれ左から6項目10項目が可変です。 10項目は、 SAのどれかに○が付いている人は、qqq+番号 SBのどれかに○が付いている人は、aaa+番号 SCのどれかに○が付いている人は、番号 という法則で可変します。 エクセルはまだまだ初心者でして、vbaを使うしかないのかそれとも 何か標準の関数を使えば解決するのかすら検討できません。 以上長くなりますが、何卒宜しく御教授お願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • keithin
  • ベストアンサー率66% (5278/7940)
回答No.2

VBAを知りたいご相談じゃなかったんですか。 手順: ブックを開く ALT+F11を押す 挿入メニューから標準モジュールを挿入する 現れたシートに下記をコピー貼り付ける sub macro1()  dim c as range  dim c0 as string  dim n as long  dim s1 as string, s2 as string, s3 as string  with range("C:I")  set c = .find(what:="○", lookin:=xlvalues, lookat:=xlwhole)  if c is nothing then exit sub  c0 = c.address  n = 5  range("A5:A65536").clearcontents  do   s1 = cells(c.row, "A").value ’number   s2 = cells(1, c.column).value ’SA1 - SC3   select case left(s2, 2) ’別にIf Thenでも全然OKです   case "SA"    s3 = "qqq"   case "SB"    s3 = "aaa"   case else    s3 = ""   end select   cells(n, "A") = "update tablename set type = " & s2 & " where user = " & s3 & s1 & " ;"   set c = .findnext(c)   n = n + 1  loop until c.address = c0  end with end sub ファイルメニューから終了してエクセルに戻る データを記入してあるシートを開く ALT+F8を押してマクロを実行する。 #まったく二度手間になっちゃいました。

torajiro123
質問者

補足

>エクセルはまだまだ初心者でして、vbaを使うしかないのかそれとも >何か標準の関数を使えば解決するのかすら検討できません。 一応こう書いておいたつもりでしたが。

その他の回答 (3)

  • keithin
  • ベストアンサー率66% (5278/7940)
回答No.4

関数の方がよかったなら。 とりあえず簡単に B5に =IF(ROW(B1)>COUNTIF($C$3:$I$4,"○"),"",INDEX(A:A,INT(SMALL(IF($C$3:$I$4="○",ROW($C$3:$I$4)*100+COLUMN($C$3:$I$5)),ROW(B1))/100))) と記入、必ずコントロールキーとシフトキーを押しながらEnterで入力、以下コピー C5に =IF(ROW(B1)>COUNTIF($C$3:$I$4,"○"),"",INDEX($1:$1,MOD(SMALL(IF($C$3:$I$4="○",ROW($C$3:$I$4)*100+COLUMN($C$3:$I$5)),ROW(C1)),100))) と記入、必ずコントロールキーとシフトキーを押しながらEnterで入力、以下コピー A5に =IF(B5="","","update tablename set type = "&C5&" where user = "&IF(LEFT(C5,2)="SA","qqq",IF(LEFT(C5,2)="SB","aaa",""))&B5&" ;") とふつーに記入、以下コピーで出来上がり。 #勘違いしないでください。あなたがあなたのつもりであるように、こちらは二度手間を踏んだという事実を指摘しているだけです。

torajiro123
質問者

お礼

嗚呼そういうことでしたか。 ご回答ありがとうございます。 関数でも確認してみます。

  • Nouble
  • ベストアンサー率18% (330/1783)
回答No.3

まずはヒントから と、その前に確認です 横並びを行、縦並びを列をします。 一例として SA2についての表示を出すヒントですが ます極々簡単なことから 空白を0、○を1と仮にします 表を見ると、上から順に 空白、○ となっていますから、これを置き換えると 0,1 ですね             ・・・(1) このままでは使えませんから これに意味を持たせます。 持たせる意味は「何行目か」です。 今回はラベル行からの距離にします。 番号111の方は1の距離 番号222の方は2の距離 ですね、 距離だけを羅列すると 1,2ですね これを先程の(1)とかけてみましょう {0,1}×{1,2}={0,2}       ・・・(2) ここまでは良いでしょうか? 本来は、もっともっと件数が在り、 恐らくは、1列に複数箇所○があるのでしょうから、 「0以外の最小の値を探す」 のではなく 「0以外の値を羅列する」 このようにしてみます。 まずは全体の件数を数えます。 今回の場合では2件ですね、 そして0以外の件数を数えます。 今回の場合では1件ですね、 (2)を大きい順に並べます 2,0 0以外だった件数まで、最大から順に取り出します。 今回は1件だけだったので 2 ですね。 表題から距離2、下の位置に該当のものがあると解ります。 さて、 ここまで一切関数の話しを入れて来ませんでしたので 各機能を実現させる関数や式をご紹介します。 まず○や空白の羅列を、0と1に変える方法です。 cのN列目までデータがあるものとしますと、 =(C3:CN="○")+0 です。 でもこれではデータ件数が増えた場合使いにくいですよね? 範囲内のデータ件数を調べるには、 「対象となるデータが数値かどうか」 などにもよりますが、 データが連続しているものとすれば COUNTA(データ範囲) がいいでしょう。 Pcの能力にもよりますが、 最近のPcなら、一列まるまるを指定しても大丈夫かも知れません。 仮にA列に何件 データが含まれるか、 これを見ていましょう。 COUNTA($A:$A)-見出しの行数(今回は1) ですね。 さて、未だ使えません、この情報だけでは… 実際のデータを可変的に、未だ読めていませんからね 可変的なデータの読み出しに使えるものは幾つかあります。 主なものとしては、OFFSET、INDEX、INDIRECT、 等がありますが、 数値を直感的に使える点から、今回はOFFSETを使いたいと思います。 OFFSETは、ヘルプにもある通り、 OFSET(基準位置、基準位置からの下をプラスとした時の距離、基準位置からの右側をプラスとした時の距離、縦方向のセル幅、横方向のセル幅) と、なっています。 例として、A3:A4を選択するようにしてみます。 仮に機銃位置をA2とします。 A3は縦方向に距離1、横方向に距離0、 A3:A4は縦方向に2の幅、横方向に1の幅ですね、 OFFSETに入れてみます。 OFFSET($a$2,1,0,2,1) 此所で「$」というものが出てきましたが、 これは、「セルをコピーした時もこの次のセル位置を決める文字を変えない」 と、いう意味です。 今回はA3:A4と 縦幅が決まっていましたからこう書きましたが、 こう書きましたが、 予めでは解らない場合は、先程のCOUNTAを使えば良いでしょう、 こうです OFFSET($a$2,1,0,COUNTA($A:$A)-1,1) (※注:今回は見出しが1行あるので1を引きました) 余談ですが、 横方向の位置も戦略的に、可変的に、知りたいですよね? そういう時はMATCHなどが使えます。 試しにデータ表表題から「SA2」を探してみます、 MATCH(1,INDEX((offset(&B&1,0,1,1,COUNTA($1:$1)),,)="SA2")*1,0) 他にも書き方は色々あるでしょうが今回はこれで、 では、任意サイズのデータ範囲の中から、表見出し"SA2"直下だけのデータ全件を取りだしてみましょう。 何件あるかは先程来と同じCOUNTA($A:%A)-1ですね 今回の基準位置はB2とします。 読出す"SA2"のあるセル群の一番上のデータセルは 縦距離が1,横距離がMATCH(1,INDEX((offset(&B&1,0,1,1,counta($1:$1)),,)="SA2")*1,0) 縦幅がCOUNTA($A:$A)-1、横幅が1、ですね 入れてみます。 OFFSET($B$2,1,MATCH(1,INDEX((offset(&B&1,0,1,1,COUNTA($1:$1)),,)="SA2")*1,0),COUNTA($A:$A)-1,1) ですね、 これについて ○ならば1,空白なら0にしてくれる先程の式を使えば良い と、いう訳です。 (OFFSET($B$2,1,MATCH(1,INDEX((offset(&B&1,0,1,1,counta($1:$1)),,)="SA2")*1,0),COUNTA($A:$A)-1,1)="○")*1 所で 「0以外の数を数える」と、云うことは 逆説的に云えば、 「1の個数を数える」と、同じ事。 ならば総和を求めたら良い… ですよね? でも問題が1つ SUM関数が問題があって使えません。 SUM関数には特殊な機能が忍ばせてあるので、 算出させる場所によって値が変動するのです。 なので こういった場合では信頼性に欠けます。 こういった場合はSUMPRODUCTを使います。 こうですね SUMPRODUCT((OFFSET($B$2,1,MATCH(1,INDEX((offset(&B&1,0,1,1,counta($1:$1)),,)="SA2")*1,0),COUNTA($A:$A)-1,1)="○")*1) ところで、 SUMPURODUCTでは1つの数字しか貰えません。 今回は最も大きいものからからn個データが欲しいのです、 ね。 最大を1、次を2、その次を… という時は{1,2,3,…}という数値が欲しいのですが、 こういう時は ROW(INDIRECT("A1:A"&n)) と、書けばn迄の連続した数値が得られます。 仮にnを5とすると、 ROW(INDIRECT("A1:A"&5)) と、書けば {1,2,3,4,5} と、なります。 先程挙げた「大きい順に並べる」は LARGEが使えます。 例としてはこうです LARGE(index({2,3,1,5,4,2,6,4,8,2,5,3,9,1},,),{1,2,3,4,5}) 取り出される答えは {9,8,6,5,5}です 大きいもの順に5つ取り出されています。 LARGE(index({2,3,1,5,4,2,6,4,8,2,5,3,9,1},,),{1}) 得られるのは{9}、最大から1番目が取り出されています。 LARGE(index({2,3,1,5,4,2,6,4,8,2,5,3,9,1},,),{1,5}) 得られるのは{9,5}、最大から1番目と、5番目が取り出されています。 後はこの取り出された0以外の表外からの距離を1つずつ使って 読出す関数OFFSETと組み合わせて 番号を知り SAやSBの時は各々qqq、aaaをつけて =CONCATENATE("update tablename set type = ",SA2(なのにデータか)," where user = ",qqq(SAに対する接尾語,読み出した番号) とすれば良いのですね。 要点は全てさらせているつもりですが、 如何でしょうか? ヒントにしては云い過ぎましたかね? 後は応用だけです。 お役に立てていたならば幸いです。

torajiro123
質問者

お礼

ヒントありがとうございます。 追いながら理解するのに、少々お時間かかりそうですね^^; 時間あるときに解読します。 ありがとうございます。

  • keithin
  • ベストアンサー率66% (5278/7940)
回答No.1

ふつーに○を探して文字列を作っていくだけです。 sub macro1()  dim c as range  dim c0 as string  dim n as long  dim s1 as string, s2 as string, s3 as string  with range("C:I")  set c = .find(what:="○", lookin:=xlvalues, lookat:=xlwhole)  if c is nothing then exit sub  c0 = c.address  n = 5  range("A5:A65536").clearcontents  do   s1 = cells(c.row, "A").value ’number   s2 = cells(1, c.column).value ’SA1 - SC3   select case left(s2, 2) ’別にIf Thenでも全然OKです   case "SA"    s3 = "qqq"   case "SB"    s3 = "aaa"   case else    s3 = ""   end select   cells(n, "A") = "update tablename set type = " & s2 & " where user = " & s3 & s1 & " ;"   set c = .findnext(c)   n = n + 1  loop until c.address = c0  end with end sub

torajiro123
質問者

補足

回答ありがとうございます。 良かったら実行の仕方の手順も加えて教えていただけますか? 初心者なものでして^^;

関連するQ&A

  • excel2003(vba)で御教授御願いします。

        A     B     C 1  番号   名前   タイプ 2  qqq111  Xさん   SA1 3  qqq222  Yさん   SA2 4  aaa111  Xさん   SB1 5  111    Xさん   SC3 6  222    Yさん   SC2 入力情報として上記のような3列からなる情報がエクセルに記入されていたとします。 A1,B1,C1にそれぞれ項目名(列名)があるとします。 番号111と222の人がC列に対して上記のようなタイプを保持しているとき 出力結果として下記の表をVBAにより自動発生させることを実現したいです。     A    B    C    D    E    F    G    H    I 1            SA1   SA2  SB1  SB2   SC1  SC2  SC3 2  番号  名前 3  111   Xさん  ○         ○                  ○ 4  222   Yさん        ○                  ○ ロジックとして、 出力結果のA列は、入力情報のA列の"数字"部分です。 頭三文字:aaa,qqqは省きます。 出力結果のB列は重複している名前を一つにして出力しています。 つまり番号列は数字部分、名前はそのままでそれぞれ重複文を 圧縮して出力します。 さらに、入力タイプ列に書かれた情報通りに○をCからI列のどれかに ○を付けます。 番号と名前は可変するとします。。 また、タイプはSA1からSC3で固定でしてこの中のいづれかに該当するとします。 動作確認を行いOKとなったソースプログラムの記述を御願い致します。 以上長くなりますが、何卒宜しく御教授お願い致します。

  • トランジスタの型番について

    古いアンプのトランジスタを交換しようと思います。 そこで分からない事があるのです。右と左は同じ物で付け替えが出来ますか。 後ろのアルファベットで何が変わるのですか。 2SC1775A と 2SC1775A-E 2SB648 と 2SB648-C と 2SB648A-C 2SD668 と 2SD668-C と 2SC668A-C 2SA968 と 2SA968B

  • トランザクションについて

    MySQLバージョン4.1.16を使っています。 トランザクションは2つに分けて行う場合と1つで済ませる場合とでは どちらが良い悪いなど違いはあるのでしょうか? できれば1つで済ませれば良いのでしょうが、 2つに分けなければいけない状態の時に、何か注意する点など出てくるのでしょうか? START TRANSACTION; UPDATE table1 SET a=1 WHERE type=1; COMMIT; START TRANSACTION; UPDATE table2 SET b=1 WHERE type=1; COMMIT; それか START TRANSACTION; UPDATE table1 SET a=1 WHERE type=1; UPDATE table2 SET b=1 WHERE type=1; COMMIT;

    • ベストアンサー
    • MySQL
  • 処理速度について(UPDATE)

    下記の2つのSQL句があります。 どのSQLが処理速度が速いのでしょうか。 また、一般的なのはどのSQLなのでしょうか。 処理1 UPDATE テーブルA SET 項目A = '0' WHERE NVL(項目A,'0') = '0'; 処理2 UPDATE テーブルA SET 項目A = '0' WHERE 項目A IS NULL; 私としては、処理2の方が早いような気がするのですが・・・ 教えてください。お願いします。

  • SqlServerのスクリプト実行について

    Windows2003ServerにてSqlServer2005をバッチファイルから実行する時について質問させてください。 下記の「sql.bat」にて「script.sql」を実行した場合、「log.txt」に出力される内容は'222'をアップデートした結果「(x行処理されました)」のみが出力されますが、'000'や'111'を更新した結果も出力させたい場合、「script.sql」を3分割し、「sql.bat」で3ファイル実行するしかないのでしょうか。 「sql.bat」 sqlcmd -S SERVERNAME -d SCHEMANAME -i c:\script.sql -o c:\log.txt 「script.sql」 update tablename set data1 = 'aaa' where data1 = '000' update tablename set data1 = 'bbb' where data1 = '111' update tablename set data1 = 'ccc' where data1 = '222'

  • 1テーブル&複数レコードの更新に対して1度のupdate文での処理方法

    1テーブル&複数レコードの更新に対して1度のupdate文での処理方法 Delphi2010+SQL SERVER 2005で開発しています。 update文で、 現在下のようにwhileで複数レコードに対して、 1回、1回、sqlを発行して、更新しています。 これを、一度のSQLの発行で処理できないものでしょうか? 更新テーブルは1つで、更新する項目も同じです。 更新するデータと、where句の条件が異なります。 もし可能なようでしたら、どうかご教授お願いします。 update table set A=1,B=2 where id=1 update table set A=2,B=3 where id=5 update table set A=9,B=99 where id=7 update table set A=5,B=10 where id=15 update table set A=1,B=10 where id=75

  • UPDATE文(副問合せ?)について

    うまく説明できないのですが、下記のようなテーブルがあります。 テーブル名:A 項目: A1 A2 A3 A4 AテーブルのA1項目に「5」がセットされているデータについて、 A2に123、A3に321をセットしたいのです。 うまくいかない例ですが、下記のようなイメージです。 UPDATE A set A2=123,A3=321 FROM (SELECT * FROM A WHERE A1 = '5') ちなみに下の書き方はダメです。 「SELECT * FROM A WHERE A1 = 5」の部分は、必ず使用し、変更不可です。 × UPDATE A set A2=123,A3=321 WHERE A1 IN(SELECT A1 FROM A WHERE A1 = 5) 変な質問ですいませんが、何か方法があるのでしょうか。 よろしくお願いします。

  • SQLでの変数の扱いについて

    VBを利用してのSQL文に変数を使いたいのですが記述方法が良くわかりません。 まず dim a as string dim b as integer dim c as integer a="AAAA" b=10 c=23500 として テーブルZの項目1が nvarchar 項目2が tinyint 項目3がrealであった場合 sql文の記述方法をWebで探していると 文字列変数ならシングルクォーテーションでくくって代入 数値変数ならダイレクトに代入というようにとれるところがあったので下記の 様に記述すると更新されません sqlstr=("UPDATE テーブルZ set 項目1='a',項目2=b,項目3=c where 項目=1") 下記のように分割してそれぞれひとつづつのテストすると更新できます sqlstr=("UPDATE テーブルZ set 項目1=" & a & " where 項目=1") sqlstr=("UPDATE テーブルZ set 項目2='" & b & "' where 項目=1") sqlstr=("UPDATE テーブルZ set 項目2='" & c & "' where 項目=1") 上記の要領で1つにまとめると出来ないので,どのように書けばよいのでしょうか よろしくお願い致します

  • UPDATE文で発生するデッドロックについて、教えてください。

    はじめまして。 SQL SERVER初心者の為、ご指導の程お願いいたします。 UPDATE文で発生するデッドロックについて教えてください。 現在、ストアドプロシージャ内で、 以下のUPDATE文を使用しています。 UPDATE テーブルA SET 更新済フラグ = '1' WHERE ロック時間 =パラメータ.ロック時間 AND ロックユーザー = パラメータ.ロックユーザー AND ID = パラメータ.ID ※Where句に使用する、ロック時間・ロックユーザー・IDは、  キー項目では無く、インデックスも使用しておりません。  ただし、対象データを一意に識別できる項目ではあります。   このストアドを含む処理を、ほぼ同時実行すると このUPDATE文で「LOCK TIMEOUT」が発生し、 デッドロックとなってしまいます。 UPDATEの対象となるデータ件数は、ともに500~600件です また、対策としましてロックのヒント文を下記のように設定し、 WHERE句に設定している、ロック時間・ロックユーザー・IDに 対して、インデックスを作成してみましたが、 同様に、デッドロックが発生してしまいます。 UPDATE テーブルA (with rowlock) SET 更新済フラグ = '1' WHERE ロック時間 = パラメータ.ロック時間 AND ロックユーザー = パラメータ.ロックユーザー AND ID = パラメータ.ID SQL Serverに詳しい方、お力になっていただければ、光栄です。 よろしくお願いいたします。

  • 複数updateする時に・・・

    やりたい事: 複数レコードのある項目を1度にupdateたい。 現在のA項目の最大値に+1した値から順にインクリメントした値を入れたい。 例: sampleというテーブルにkey,dataという項目があったとします。 update前 >>> update後 key|data______key|data --+----______--+---- _A_|_1___________A_|_1_ _B_|_2___________B_|_2_ _C_|_3___________C_|_3_ _A_|_0___________A_|_4_ _A_|_0___________A_|_5_ _A_|_0___________A_|_6_ (スペースが入らなくて_にしました見にくいですが) 同じ値をupdateするなら update sample set data=値 where key=A and data=0 これを update sample set data=MAX(data)++ where key=A and data=0 みたいに書けたらいいなぁと思うのですが、1度該当レコードをselectして取得した値を条件に順番に1行づつupdateしないとだめですかね・・・ ちなみに環境はRedHat7.0J上のPostgreSQL7.0.2 です。

専門家に質問してみよう