【问题标题】:INSERT INTO table2 SELECT FROM table1 then UPDATE table1 rows that selected/insertedINSERT INTO table2 SELECT FROM table1 然后 UPDATE table1 选择/插入的行
【发布时间】:2016-11-07 05:47:33
【问题描述】:

我正在编写一个将数据从表 data_entry 复制到另一个表 promotional 的过程 data_entry的表结构如下(排除非相关字段)-

CREATE TABLE `data_entry` (
  `school_id` int(11) NOT NULL AUTO_INCREMENT,
  `school_name` varchar(255) NOT NULL,
  `mobile_number` varchar(15) DEFAULT NULL,
  `email` varchar(50) DEFAULT NULL,
  `website` varchar(255) DEFAULT NULL,
  `city` varchar(250) DEFAULT NULL,
  `pin` varchar(6) DEFAULT NULL,
  `is_copied_to_promo` tinyint(4) DEFAULT '0'
  PRIMARY KEY (`school_id`)
)

promotional的表结构(排除非相关字段)

CREATE TABLE `promotional` (
      `promo_id` int(11) NOT NULL AUTO_INCREMENT, //renamed to avoid confusion
      `school_name` varchar(255) NOT NULL,
      `mobile_number` varchar(15) DEFAULT NULL,
      `email` varchar(50) DEFAULT NULL,
      `website` varchar(255) DEFAULT NULL,
      `city` varchar(250) DEFAULT NULL,
      `pin` varchar(6) DEFAULT NULL,
      `copied_school_id` INT, // edit - school_id of data_entry table will go here
       PRIMARY KEY (`promo_id`)
   )

这是将所有行从data_entry 复制到promotional 的过程,其中is_copied_to_promo=0

程序

CREATE PROCEDURE `uspCopySchoolsToPromotional`(IN param_insert_datetime DATETIME)
BEGIN
    INSERT IGNORE INTO promotional (
      school_name,
      mobile_number,
      email,
      website,             
      city,
      pin,
      copied_school_id                                   
    )
SELECT school_name,
    mobile_number,
    email,
    website,
    city,
    pin,
    school_id
FROM data_entry
  WHERE is_copied_to_promo =0 ;
END;

我现在想要将data_entry 表中的is_copied_to_promo 更新为1,以更新上述过程中所有插入/受影响的行,以便每次执行上述过程时,只有data_entry 表中的新行复制到促销。

我通过PHP 代码调用此过程。解决方案可以是在同一过程中添加更新查询,也可以在执行uspCopySchoolsToPromotional 后运行另一个查询/过程。

提前致谢。

编辑:

我忘了提到两个表中的 school_id 是不同的。在促销表中,数据来自多个来源。所以我在促销表中将school_id 重命名为promo_id 以避免您的混淆。

【问题讨论】:

    标签: php mysql stored-procedures insert-update


    【解决方案1】:

    如果您也复制了 school_id,那么您就有一个唯一的密钥可供使用,然后您可以在 INSERT 之后添加一个 UPDATE 来执行此操作,例如:

    CREATE PROCEDURE `uspCopySchoolsToPromotional`(IN param_insert_datetime DATETIME)
    BEGIN
        INSERT IGNORE INTO promotional (
          school_id, 
          school_name,
          mobile_number,
          email,
          website,             
          city,
          pin                                   
        )
    SELECT school_id,
        school_name,
        mobile_number,
        email,
        website,
        city,
        pin,
    FROM data_entry
      WHERE is_copied_to_promo =0 ;
    
    UPDATE data_entry 
        SET is_copied_to_promo=1 
    WHERE 
        school_id=(SELECT school_id FROM promotional) 
        AND is_copies_to_promo=0;
    END;
    

    希望这会有所帮助:)

    【讨论】:

    • 对不起。我忘了提到两个表中的 school_id 是不同的。在促销表中,数据来自多个来源。其中之一是data_entry table。
    • school_name 值是否唯一?如果是的话,你可以在 UPDATE WHERE 子句中进行匹配:)
    • 学校名称不是唯一的。但是如果我在promotional 表中添加一个新列copied_school_id 并且data_entry 表中的school_id 将插入其中。在这种情况下,您可以提供帮助。
    【解决方案2】:

    Mysql 8 应该有 Common Table Expressions 但它似乎没有出现在release announcements 中,所以你必须使用其他一些机制来实现它。一种解决方案是使用after insert trigger

    CREATE TRIGGER data_entry  AFTER INSERT ON promotional_update
    FOR EACH ROW
    BEGIN
       UPDATE data_entry SET 
          WHERE is_copied_to_promo = 1 WHERE school_id = new.ID;
    END
    

    另一种解决方案是在插入后获取表级锁并更新

    CREATE PROCEDURE `uspCopySchoolsToPromotional`(IN param_insert_datetime DATETIME)
    BEGIN
       LOCK TABLES data_entry WRITE;
        ....
    
    
        UPDATE data_entry 
            SET is_copied_to_promo=1 
        WHERE 
            school_id=(SELECT school_id FROM promotional) 
            AND is_copies_to_promo=0;
    
        UNLOCK TABLES:
    END;
    

    请注意,如果您不锁定表,您可能会发现竞争条件会导致不一致。这两种方法(触发与锁定和更新)各有利弊。

    【讨论】:

    • 将尝试触发选项并通知您。
    【解决方案3】:

    如果您在两个表中都没有 School_id 作为 auto_increment,您可以按照 Flauntster 的查询。

    如果两个表中的列都是auto_increment,那么你可以按照下面的查询

    CREATE PROCEDURE `uspCopySchoolsToPromotional`(IN param_insert_datetime DATETIME)
    BEGIN
        INSERT IGNORE INTO promotional (
          school_id, 
          school_name,
          mobile_number,
          email,
          website,             
          city,
          pin                                   
        )
    SELECT school_id,
        school_name,
        mobile_number,
        email,
        website,
        city,
        pin,
    FROM data_entry
      WHERE is_copied_to_promo =0 ;
    
    UPDATE data_entry de
    JOIN promotional p ON de.school_name = p.school_name 
        AND de.mobile_number = p.mobile_number 
        AND is_copies_to_promo = 0
        SET is_copied_to_promo=1;
    END;
    

    希望这能解决您的问题。

    【讨论】:

      猜你喜欢
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-15
      • 1970-01-01
      • 2014-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多