web-dev-qa-db-ja.com

mysql sprocのテーブル名に変数を使用する

私はこのsprocを使用して異なるテーブルから選択するためにテーブル名をmysqlストアドプロシージャに渡そうとしていますが、うまくいきません...

これは私が試していることです:

CREATE PROCEDURE `usp_SelectFromTables`(
 IN TableName varchar(100)
)
BEGIN
        SELECT * FROM @TableName;
END

また、@記号なしで試してみましたが、TableNameが存在しないことがわかります...私は知っています:)

26
Kyle

DBMSに依存しますが、表記法には通常ダイナミックSQLが必要であり、実行時の関数からの戻り値が入力に依存するという問題が発生します。これにより、システムの接続が失われます。一般的な規則として(したがって、おそらく例外の対象となります)、DBMSでは、テーブル名や列名などのクエリの構造要素にプレースホルダー(パラメーター)を使用できません。列値などの値のみを指定できます。

一部のDBMSには、「prepare」または「execute immediate」などの操作を使用して、SQL文字列を作成して操作できるストアドプロシージャのサポートがあります。ただし、突然SQLインジェクション攻撃に対して脆弱であることに注意してください。プロシージャを実行できる人は、SQLの実行を部分的に制御できるようになります。

13
SET @cname:='jello';
SET @vname:='dwb';
SET @sql_text = concat('select concept_id,concept_name,',@vname,' from enc2.concept a JOIN enc2.ratings b USING(concept_id) where concept_name like (''%',@cname,'%'') and 3 is not null order by 3 asc');

PREPARE stmt FROM @sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
54
Angelo

問題を引き起こした余分なビット。

@kyleが尋ねたように、クエリでテーブル名とフィールドを動的に設定したかったのですが、クエリ内の変数@aにそのクエリの結果を保存したかったのです。

変数@aconcatにそのまま入れるのではなく、文字列テキストの一部として含める必要があります。

delimiter //

CREATE PROCEDURE removeProcessed(table_name VARCHAR(255), keyField VARCHAR(255), maxId INT, num_rows INT)

BEGIN
  SET @table_name = table_name;
  SET @keyField = keyField;
  SET @maxId = maxId;
  SET @num_rows = num_rows;

  SET @sql_text1 = concat('SELECT MIN(',@keyField,') INTO @a FROM ',@table_name);
  PREPARE stmt1 FROM @sql_text1;
  EXECUTE stmt1;
  DEALLOCATE PREPARE stmt1;

  loop_label:  LOOP
    SET @sql_text2 = concat('SELECT ',@keyField,' INTO @z FROM ',@table_name,' WHERE ',@keyField,' >= ',@a,' ORDER BY ',@keyField,' LIMIT ',@num_rows,',1');
    PREPARE stmt2 FROM @sql_text2;
    EXECUTE stmt2;
    DEALLOCATE PREPARE stmt2;

    ...Additional looping code...

    END LOOP;
END
//

delimiter ;

したがって、@sql_text1では、次を使用して文字列内の@aにクエリの結果を割り当てます。

') INTO @a FROM '

次に、@sql_text2で実際の変数として@aを使用します。

,' WHERE ',@keyField,' >= ', @ a,' ORDER BY '

14
codewaggle