【问题标题】:MySQL Trigger - Storing a SELECT in a variableMySQL 触发器 - 将 SELECT 存储在变量中
【发布时间】:2010-09-24 09:18:13
【问题描述】:

我有一个触发器,我希望有一个变量来保存我从SELECT 获得的 INT,因此我可以在两个 IF 语句中使用它,而不是两次调用SELECT。如何在 MySQL 触发器中声明/使用变量?

【问题讨论】:

    标签: mysql sql triggers


    【解决方案1】:

    您可以在 MySQL 触发器中声明局部变量,使用 DECLARE 语法。

    这是一个例子:

    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”。

    您可以使用LIMITMAX() 确保将局部变量设置为单个值。

    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//
    

    【讨论】:

    • 是否可以将结果集存储在变量中,还是必须发出单独的查询?
    • 不,一个变量只能存储一个值。您必须为变量声明 SQL 数据类型,就像为表的列声明一样。 MySQL 中没有存储结果集的数据类型。
    • 很遗憾用户不在身边接受这个答案,因为它是正确的。
    • @Akash 触发器正文中的查询是在触发器执行时执行的,而不是在定义触发器时执行的。您可以通过将查询结果分配给会话变量(以@ 为前缀)来测试这一点,以便在插入完成后该变量将具有该值。然后您可以检查会话变量中的值。
    • @Akash,使用USER() 函数,而不是CURRENT_USER()。阅读dev.mysql.com/doc/refman/8.0/en/…:“触发器和事件没有选项来定义 SQL SECURITY 特性,因此对于这些对象,CURRENT_USER() 返回定义对象的用户的帐户。要返回调用者,请使用 USER()或 SESSION_USER()。"
    【解决方案2】:
    `CREATE TRIGGER `category_before_ins_tr` BEFORE INSERT ON `category`
      FOR EACH ROW
    BEGIN
        **SET @tableId= (SELECT id FROM dummy LIMIT 1);**
    
    END;`;
    

    【讨论】:

    • 我编辑了这个以进行格式化,因此您可能需要检查以确保它在语法上仍然正确。
    【解决方案3】:
    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

    【讨论】:

      【解决方案4】:

      我发布此解决方案是因为我很难找到我需要的东西。这篇文章让我足够接近(+1 表示感谢),这是如果数据与测试匹配,则在插入之前重新排列列数据的最终解决方案。

      注意:这是来自一个遗留项目我继承的位置:

      1. 唯一键是rridprefix + rrid 的组合
      2. 在我接手之前,没有任何约束可以防止重复唯一键
      3. 我们需要将两个表(一个充满重复项)合并到现在对复合键有约束的主表中(因此合并失败,因为获取表不允许来自不干净表的重复项)
      4. on duplicate key 不太理想,因为列太多并且可能会更改

      无论如何,这里的触发器将任何重复的键放入旧列,同时允许我们存储旧的、错误的数据(而不是触发获取表的复合唯一键)。。 p>

      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
      

      【讨论】:

        【解决方案5】:

        或者您可以只在调用触发器的 SQL 中包含 SELECT 语句,因此它作为触发器行中的列之一传入。只要您确定它只会返回一行(因此只有一个值)。 (当然,它不能返回与触发器中的逻辑交互的值,但无论如何都是如此。)

        【讨论】:

          【解决方案6】:

          我想我理解你的问题 我相信你可以简单地在“DECLARE”中声明你的变量 然后在“开始”之后你可以使用“选择进入”你的变量“”语句。 代码如下所示:

          DECLARE
          YourVar  varchar(50);
          begin 
          select ID into YourVar  from table
          where ...
          

          【讨论】:

          • 这在 MYSQL 中不起作用,我已经按照您描述的方式进行了尝试,但它不会将数据加载到 var 中。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-08
          • 1970-01-01
          • 2012-09-16
          • 1970-01-01
          • 2016-10-07
          • 1970-01-01
          相关资源
          最近更新 更多