MySQL使用一条Insert语句代替游标循环

MySQL使用一条Insert语句代替游标循环,mysql,performance,cursor,insert-into,Mysql,Performance,Cursor,Insert Into,我有这个触发器,它工作得很好,但我读到使用游标和循环对性能没有好处 所以,我如何用一个insert into语句替换cursor和loop,就像update部分中的那个语句一样: CREATE TRIGGER `after_insert_invoice` AFTER INSERT ON `invoicetbl` FOR EACH ROW BEGIN DECLARE v_finished INTEGER DEFAULT 0; DECLARE my_hour INT(11) DEFAULT

我有这个触发器,它工作得很好,但我读到使用游标和循环对性能没有好处

所以,我如何用一个insert into语句替换cursor和loop,就像update部分中的那个语句一样:

CREATE TRIGGER `after_insert_invoice` AFTER INSERT ON `invoicetbl`
 FOR EACH ROW BEGIN
  DECLARE v_finished INTEGER DEFAULT 0;
  DECLARE my_hour INT(11) DEFAULT 0;
  DECLARE my_day INT(11) DEFAULT 0;
  DECLARE my_month INT(11) DEFAULT 0;
  DECLARE current_item_id BINARY(16);
  DECLARE current_item_total_price DECIMAL(11, 2);
  DECLARE current_item_count DECIMAL(11, 3);

  DECLARE cur CURSOR FOR     SELECT  item_id, item_total_price, item_count
        FROM  invoice_itemtbl
        WHERE  invoice_id = NEW.invoice_id;

  DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1;

  SET my_month = EXTRACT(YEAR_MONTH FROM NEW.invoice_date);
  SET my_day = CONCAT(my_month, LPAD(DAY(NEW.invoice_date), 2, '0'));
  SET my_hour = CONCAT(my_day, LPAD(HOUR(NEW.invoice_date), 2, '0'));

  IF NEW.invoice_type = 0 THEN

        OPEN cur;

        start_loop: LOOP

        FETCH cur INTO current_item_id,
                       current_item_total_price,
                       current_item_count;

        IF v_finished = 1 THEN 
            LEAVE start_loop;
        ELSE
继续

        INSERT
          INTO  sales_result_company_item_month(company_id, currency_id,
                time_value, item_id, result, invoices_count, item_qty )
          VALUES  (NEW.company_id, NEW.currency_id, my_month, current_item_id,
                    current_item_total_price, 1, current_item_count )
          ON DUPLICATE KEY 
          UPDATE  result = result + current_item_total_price,
                  invoices_count = invoices_count + 1,
                  item_qty = item_qty + current_item_count;

        END IF;
        END LOOP;

      CLOSE cur;

  END IF;

  IF NEW.invoice_type = 1 THEN

    //like here:
    UPDATE  sales_result_company_item_month m
    INNER JOIN  
    (
        SELECT  item_id, returns_count, returns_total
            FROM  invoice_returns
            WHERE  return_invoice_id = NEW.invoice_id
    ) f  ON m.item_id = f.item_id SET m.result = m.result - f.returns_total,
        m.item_qty = m.item_qty - f.returns_count
    WHERE  m.company_id = NEW.company_id
      AND  m.currency_id = NEW.currency_id
      AND  m.time_value = my_month;

  END IF;

END
从注释中复制-在“修复”问题后,包括删除光标:

INSERT
     INTO  sales_result_company_item_month
         (company_id, currency_id, time_value, item_id,
          result, invoices_count, item_qty) 
SELECT  NEW.company_id, NEW.currency_id, my_month, t.item_id,
        t.item_total_price, 1, t.item_count
    FROM  invoice_itemtbl t
    WHERE  invoice_id = NEW.invoice_id
    ON DUPLICATE KEY UPDATE 
        result = result + t.item_total_price,
        invoices_count = invoices_count + 1,
        item_qty = item_qty + t.item_count;

是的,您可能可以摆脱光标

这是可能的

INSERT INTO t ( ... )
    ON DUPLICATE KEY UPDATE ...
    SELECT ...;
在这种情况下,SELECT将获取所有要向上插入的行。您可能需要UPDATE子句中的值来区分所选列和表中已有的列。参见手册中的示例

如果你想进一步讨论这个问题,请

为相关表格提供SHOW CREATE TABLE, 扔掉那些没用过的kruft(如my_day) 在局部变量前面加上x前缀,或者将它们与表列区分开来。
当前项目计数小数11,3让我困惑:什么计数需要3位小数?

是的,您可能可以去掉光标

这是可能的

INSERT INTO t ( ... )
    ON DUPLICATE KEY UPDATE ...
    SELECT ...;
在这种情况下,SELECT将获取所有要向上插入的行。您可能需要UPDATE子句中的值来区分所选列和表中已有的列。参见手册中的示例

如果你想进一步讨论这个问题,请

为相关表格提供SHOW CREATE TABLE, 扔掉那些没用过的kruft(如my_day) 在局部变量前面加上x前缀,或者将它们与表列区分开来。
当前项目计数小数11,3让我困惑:什么计数需要3位小数?

非常感谢。这是结果查询:插入到销售\结果\公司\项目\月份公司\ id、货币\ id、时间\值、项目\ id、结果、发票\计数、项目\数量选择NEW.company\ id、NEW.currency\ id、my\ u month、t.item\ id、t.item\总价,1,从发票项目TBL t计算项目数量,其中发票id=新。重复键更新结果上的发票id=结果+项目总价,发票数量=发票数量+1,项目数量=项目数量+项目数量;当前项目计数是INT11,我更改了类型,但没有更改名称。谢谢。我在你的问题中添加了你的解决方案——供其他读者参考。非常感谢。这是结果查询:插入到销售\结果\公司\项目\月份公司\ id、货币\ id、时间\值、项目\ id、结果、发票\计数、项目\数量选择NEW.company\ id、NEW.currency\ id、my\ u month、t.item\ id、t.item\总价,1,从发票项目TBL t计算项目数量,其中发票id=新。重复键更新结果上的发票id=结果+项目总价,发票数量=发票数量+1,项目数量=项目数量+项目数量;当前项目计数是INT11,我更改了类型,但没有更改名称。谢谢。我在你的问题中添加了你的解决方案——供其他读者参考。