table1のフィールドがsql1のみで内容はsqlのupdate文が格納されてい
ます。そして、このtable1のsql1を読んでその内容で更新クエリーを実
行するとした場合は、どの様にmysqlでは処理を記述すれば良いのかと
言うのが分かりません。
例えば、table1が下記の場合はどう言う記述になるのでしょうか。
update result1 set target1=7 where id between 1 and 13;
update result1 set target1=12 where id between 14 and 20;
update result1 set target1=20 where id between 21 and 31;
この場合は、table1を読んで、sql1の更新クエリーを実行したいのです
が。個別にレコード単位に処理をする所がプロシージャをどの様に使う
のかと言うのが良く分かりません。
済みません。sqlの例示をお願いします。
No.5ベストアンサー
- 回答日時:
>SET @sql=CONCAT('update result1 set target1=? where id between ? and ?;');
>上記で、?をブレースホルダーと言い、
まぁプレースホルダ自体は比較的一般的なIT用語ですね
http://e-words.jp/w/%E3%83%97%E3%83%AC%E3%83%BC% …
>EXECUTE stmt USING @a,@b,@c;
>この時に実際の指定をするのがバインドと言う事でしょうか。
私もプロではないので、厳密な用語として正しいかどうかといわれると怪しいですが
そういう認識でよいかと思います
https://dev.mysql.com/doc/refman/5.6/ja/sql-synt …
>PREPARE stmt FROM @sql;
>上記で、指定をするのは概観だけで実際の正確な指定は実行時に指定をする
>と言う方法の事をここではブレースホルダーの指定と言うのでしょうか。
プリペア(もしくはプリペアド)の処理を指定してるという言い方の方がわかりやすいのでは?
実行自体はEXECUTEの構文になるので
https://dev.mysql.com/doc/refman/5.6/ja/prepare. …
No.4
- 回答日時:
>',a,'とか、',b,'とか、',c,'とかは何故ここにコンマが前後に入らないといけないのでしょうか。
MYPROCEDURE2について
SELECT val,start_id,end_id FROM table2;
で得た、カーソルをそれぞれaにval、bにstart_id、cにend_idを代入してあり
@sql変数にCANCATでつなげて代入しているわけです。
その後stmtに反映して実行しています
MYPROCEDURE3について
>SET @a=a,@b=b,@c=c;が@sql=concatの括弧の中に引数として展開をすると言う事でしょうか。
MYPROPCEDURE2と同様、a,b,cで受けたval,start_id,end_idをプリペアド処理するために
変数@a,@b,@cにいれておき、EXECUTEする際に、該当位置に展開しています
プレースホルダの基本的な表記方法です
MYPROCEDUREの2と3の違いは、プレースホルダを有効につかっているかです。
とくに3の書式であればプロシージャの外側から来た汚染されたインジェクションデータであっても
安全に運用することができます。
今回は結局table2から渡されたデータをつかっているだけなので、
セキュリティ的にもあまり大きな違いはありません。
有難う御座います。
プレースホルダーとか、インジェクションデータとか初めて聞く言葉です。
この辺が書かれている本とかが有りましたら教えて貰えないでしょうか。
どうも、この辺の内容は見当たらない様な気がする物ですから。
No.3
- 回答日時:
ちなみに・・・
CREATE TABLE table2(val int,start_id int,end_id int);
INSERT INTO table2 VALUES(7,1,13),(12,14,20),(20,21,31);
としておいて値を利用して更新する手もあります。
DROP PROCEDURE IF EXISTS MYPROCEDURE2;
DELIMITER //
CREATE PROCEDURE MYPROCEDURE2()
BEGIN
DECLARE a,b,c VARCHAR(100);
DECLARE done INT DEFAULT 0;
DECLARE CUR CURSOR FOR SELECT val,start_id,end_id FROM table2;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN CUR;
REPEAT
FETCH CUR INTO a,b,c;
IF NOT done THEN
SET @sql=CONCAT('update result1 set target1=',a,' where id between ',b,' and ',c,';');
PREPARE stmt FROM @sql;
EXECUTE stmt;
END IF;
UNTIL done END REPEAT;
CLOSE CUR;
END
//
DELIMITER ;
UPDATE result1 SET target1=0;
CALL MYPROCEDURE2;
また、せっかくプリペアド処理をしているのですから、それらしく書いても良いでしょう
(外からデータを持ってくるわけではなく、データ型も分かっているのでプリペアドに処理する必要はないですが)
DROP PROCEDURE IF EXISTS MYPROCEDURE3;
DELIMITER //
CREATE PROCEDURE MYPROCEDURE3()
BEGIN
DECLARE a,b,c VARCHAR(100);
DECLARE done INT DEFAULT 0;
DECLARE CUR CURSOR FOR SELECT val,start_id,end_id FROM table2;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN CUR;
REPEAT
FETCH CUR INTO a,b,c;
IF NOT done THEN
SET @a=a,@b=b,@c=c;
SET @sql=CONCAT('update result1 set target1=? where id between ? and ?;');
PREPARE stmt FROM @sql;
EXECUTE stmt USING @a,@b,@c;
END IF;
UNTIL done END REPEAT;
CLOSE CUR;
END
//
DELIMITER ;
UPDATE result1 SET target1=0;
CALL MYPROCEDURE3;
それと、今回はUPDATEを実行するデータが競合していませんが、
本来であれば競合を想定して、実行するSQLに順位をつけるべきです。
プロシージャ内でtable1(table2)からデータを抜き出す際に
何らかのキーをもとにORDER BYを指定して実行順位を確定してください。
有難う御座います。
いつもお世話になっています。
最初のprocedure2のSET @sql=CONCAT('update result1 set target1=',a,' where id between ',b,' and ',c,';');が良く分かりません。
',a,'とか、',b,'とか、',c,'とかは何故ここにコンマが前後に入らないといけないのでしょうか。これは、変数を展開が出来ると言う事でしょうか。実際は展開をしているのですが。
これはこの様な使い方が出来ると言う事でしょうか。
それと次のprocedure3のSET @a=a,@b=b,@c=c;
SET @sql=CONCAT('update result1 set target1=? where id between ? and ?;');
上記は、SET @a=a,@b=b,@c=c;が@sql=concatの括弧の中に引数として展開をすると言う事でしょうか。
この二点が良く分かりません。
No.2
- 回答日時:
>sqlstateの値が'02000'
については、ここを参照
https://dev.mysql.com/doc/refman/5.6/ja/declare- …
ようは普通にエラーを利用して制御する処理です
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
ってことで、データがなくなった終了フラグを立てる感じですかね
データを走査して処理するのであれば、この方法が一般的なようです
マニュアルの複合ステートメント構文全般をご一読されると理解が深まると思います
https://dev.mysql.com/doc/refman/5.6/ja/sql-synt …
No.1
- 回答日時:
例えば・・・
CREATE TABLE table1 (sql1 varchar(100));
INSERT INTO table1 VALUES('update result1 set target1=7 where id between 1 and 13;'),('update result1 set target1=12 where id between 14 and 20;'),('update result1 set target1=20 where id between 21 and 31;');
CREATE TABLE result1 (id int not null,target1 int not null default 0);
INSERT INTO result1(id) VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),(30),(31),(32);
こうだったときに、table1のSQL文をつかってresult1のテーブルを更新したいということ?
今までの質問の流れからじきにこういった質問くるとは思ったけど、意外に早かった
カーソルとハンドラとプリペアド処理、慣れるまではちょっと面倒かも
以下サンプル
DROP PROCEDURE IF EXISTS MYPROCEDURE;
DELIMITER //
CREATE PROCEDURE MYPROCEDURE()
BEGIN
DECLARE a VARCHAR(100);
DECLARE done INT DEFAULT 0;
DECLARE CUR CURSOR FOR SELECT sql1 FROM table1;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN CUR;
REPEAT
FETCH CUR INTO a;
IF NOT done THEN
SET @sql=a;
PREPARE stmt FROM @sql;
EXECUTE stmt;
END IF;
UNTIL done END REPEAT;
CLOSE CUR;
END
//
DELIMITER ;
→一度resul1を初期化
UPDATE result1 SET target1=0;
→プロシージャ実行
CALL MYPROCEDURE;
→確認
SELECT * FROM result1;
有難う御座います。
動く事は確認が取れました。少し質問が有ります。
declare continue handler for sqlstate '02000' set done = 1;
上記の宣言の意味は、ローカル変数としてcontinueの名前でハンドラー
を宣言する。
continueのハンドラーは、sqlstateの値が'02000'の時に変数done=1に
する。
と言う意味でしょうか。ここで、sqlstate '02000'の意味が良く分かり
ませんが。これは、カーソルにデータが存在をしている事を示している
のでしょうか。あるいはその逆でしょうか。
と言うのはこれを繰り返しの条件にしているので。
私は、この繰り返しに付いてはtable1のレコード件数と比較をしての繰
り返しを考えていたのですが。これが一般的な方法でしょうか。
ここで、ハンドラーとsqlstateの当りが良く分かりません。済みませ
ん。教えて下さい。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PHP php エラー 2 2022/10/23 16:43
- その他(データベース) 更新クエリをリンクデータベーステーブルに実行し実行時エラー3362固有インデックスに重複する値が含ま 1 2022/09/21 11:44
- Access(アクセス) DoCmd.SearchForRecord が動かない時の解決方法 3 2022/07/22 15:31
- Visual Basic(VBA) vbaのエラー対応(実行時エラー7:メモリが不足しています) 4 2023/04/24 00:20
- Visual Basic(VBA) ファイル全てを .xlsm に変更したところ、プログラムが途中で落ちてしまっています 17 2022/12/07 12:03
- Visual Basic(VBA) エクセルVBA(実行時エラー438)の対処法を教えてもらえないでしょうか 3 2023/04/22 13:43
- Access(アクセス) アクセス where句を使用して複数条件抽出をするには 2 2022/08/29 13:24
- Access(アクセス) アクセス テーブルの空白を変数に置換するボタンが作りたい 4 2022/07/08 11:19
- Visual Basic(VBA) ExcelからAccessのテーブルに書き込む時に時間がかかる 1 2022/10/14 20:38
- Visual Basic(VBA) 【VBA】写真の貼り付けコードがうまく機能しません。 5 2022/09/01 18:43
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
エクセルで最後の文字だけ置き...
-
[MySQL] 3つのテーブルの結合で...
-
エクセルの関数について教えて...
-
sqlで、600行あるテーブルを100...
-
SQLサーバから、項目の属性(型...
-
上位3位を求めるSQL文は?
-
副問合せの書き方について
-
SQL Left Join で重複を排除す...
-
SQLにて特定の文字を除いた検索...
-
[MySQL] UNIQUE制約の値を更新...
-
Access パラメータクエリをcsv...
-
selectした大量データをinsert...
-
親と子供が複数のSQL取得方法
-
テーブルが5つの時の結合の仕...
-
書籍の内容はまともでしょうか?
-
クエリ表示と、ADOで抽出したレ...
-
【SQL文】Insert into文で文法...
-
VIEWの元のテーブルのindexって...
-
inner joinをすると数がおかし...
-
Mysqlでunionを使った検索速度...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
エクセルで最後の文字だけ置き...
-
SQL Left Join で重複を排除す...
-
SQLサーバから、項目の属性(型...
-
副問合せの書き方について
-
VIEWの元のテーブルのindexって...
-
エクセルの関数について教えて...
-
SQLにて特定の文字を除いた検索...
-
マイクラPC版のコマンドで効率...
-
select文のwhere句に配列を入れ...
-
sqlで、600行あるテーブルを100...
-
ある条件の最大値+1を初番する...
-
inner joinをすると数がおかし...
-
Unionした最後にGROUP BYを追加...
-
期間の重複を調べるSQL文につい...
-
クエリ表示と、ADOで抽出したレ...
-
Access パラメータクエリをcsv...
-
PL/SQLの変数について
-
MySQLのDATE型カラム値がNULLの...
-
php+mysqlで複数選択削除について
-
上位3位を求めるSQL文は?
おすすめ情報
SET @sql=CONCAT('update result1 set target1=? where id between ? and ?;');
上記で、?をブレースホルダーと言い、
EXECUTE stmt USING @a,@b,@c;
この時に実際の指定をするのがバインドと言う事でしょうか。
PREPARE stmt FROM @sql;
上記で、指定をするのは概観だけで実際の正確な指定は実行時に指定をする
と言う方法の事をここではブレースホルダーの指定と言うのでしょうか。