web-dev-qa-db-ja.com

MySQLトリガー-SELECTを変数に保存する

SELECTから取得したINTを保持する変数が必要なトリガーがあるため、SELECTを2回呼び出す代わりに、2つのIFステートメントで使用できます。 MySQLトリガーで変数をどのように宣言/使用しますか?

53
Ice

DECLARE構文を使用して、MySQLトリガーでローカル変数を宣言できます。

以下に例を示します。

_DROP TABLE IF EXISTS foo;
CREATE TABLE FOO (
  i SERIAL PRIMARY KEY
);

DELIMITER //
DROP TRIGGER IF EXISTS bar //

CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
  DECLARE x INT;
  SET x = NEW.i;
  SET @a = x; -- set user variable outside trigger
END//

DELIMITER ;

SET @a = 0;

SELECT @a; -- returns 0

INSERT INTO foo () VALUES ();

SELECT @a; -- returns 1, the value it got during the trigger
_

変数に値を割り当てる場合、クエリが単一の値のみを返し、行のセットまたは列のセットではないことを確認する必要があります。たとえば、クエリが実際に単一の値を返す場合は問題ありませんが、複数の行を返すとすぐに「_ERROR 1242: Subquery returns more than 1 row_」を取得します。

LIMITまたはMAX()を使用して、ローカル変数が単一の値に設定されていることを確認できます。

_CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
  DECLARE x INT;
  SET x = (SELECT age FROM users WHERE name = 'Bill'); 
  -- ERROR 1242 if more than one row with 'Bill'
END//

CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
  DECLARE x INT;
  SET x = (SELECT MAX(age) FROM users WHERE name = 'Bill');
  -- OK even when more than one row with 'Bill'
END//
_
49
Bill Karwin
`CREATE TRIGGER `category_before_ins_tr` BEFORE INSERT ON `category`
  FOR EACH ROW
BEGIN
    **SET @tableId= (SELECT id FROM dummy LIMIT 1);**

END;`;
7
IgorS
CREATE TRIGGER clearcamcdr AFTER INSERT ON `asteriskcdrdb`.`cdr` 
FOR EACH ROW
BEGIN
  SET @INC = (SELECT sip_inc FROM trunks LIMIT 1);
  IF NEW.billsec >1 AND NEW.channel LIKE @INC 
    AND NEW.dstchannel NOT LIKE "" 
  THEN
    insert into `asteriskcdrdb`.`filtre` (id_appel,date_appel,source,destinataire,duree,sens,commentaire,suivi) 
      values (NEW.id,NEW.calldate,NEW.src,NEW.dstchannel,NEW.billsec,"entrant","",""); 
  END IF;
END$$

これを@ homeにしないでください

6
autobulkvm

または、トリガーを呼び出すSQLにSELECTステートメントを含めるだけで、トリガー行の列の1つとして渡すことができます。確実である限り、確実に1行のみを返します(したがって1つの値)。 (そしてもちろん、トリガーのロジックと相互作用する値を返すことはできませんが、それはいずれの場合にも当てはまります。)

2
dkretz

必要なものを見つけるのに苦労したため、このソリューションを投稿しています。この投稿で私は十分に近くなりました(ありがとうございました+1)。これがデータがテストに一致する場合、挿入前に列データを再配置するの最終的な解決策です。

注:これはレガシープロジェクトからのものです。

  1. 一意のキーは、rridprefix + rridの複合です
  2. 私が引き継ぐ前に、重複する一意キーを妨げる制約はありませんでした
  3. 2つのテーブル(1つは重複でいっぱい)を複合キーに制約を持つメインテーブルに結合する必要がありました(そのため、取得中のテーブルではクリーンでないテーブルからの重複が許可されないため、マージは失敗します)
  4. on duplicate keyは、列が多すぎて変更される可能性があるため、理想的とは言えません。

とにかく、ここで、重複するキーをレガシー列に入れ、レガシーの不正なデータを格納できるようにします(取得テーブルの複合、一意のキーをトリガーしません)

BEGIN
  -- prevent duplicate composite keys when merging in archive to main
  SET @EXIST_COMPOSITE_KEY = (SELECT count(*) FROM patientrecords where rridprefix = NEW.rridprefix and rrid = NEW.rrid);

  -- if the composite key to be introduced during merge exists, rearrange the data for insert
  IF @EXIST_COMPOSITE_KEY > 0
  THEN

    -- set the incoming column data this way (if composite key exists)

    -- the legacy duplicate rrid field will help us keep the bad data
    SET NEW.legacyduperrid = NEW.rrid;

    -- allow the following block to set the new rrid appropriately
    SET NEW.rrid = null;

  END IF;

  -- legacy code tried set the rrid (race condition), now the db does it
  SET NEW.rrid = (
    SELECT if(NEW.rrid is null and NEW.legacyduperrid is null, IFNULL(MAX(rrid), 0) + 1, NEW.rrid)
    FROM patientrecords
    WHERE rridprefix  = NEW.rridprefix
  );
END
1
WEBjuju