INSERT INTO table2 SELECT FROM table1然后UPDATE table1选择/插入的行

时间:2016-11-07 05:47:33

标签: php mysql stored-procedures insert-update

我正在编写一个将数据从表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;

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

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

提前致谢。

编辑:

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

3 个答案:

答案 0 :(得分: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;

希望这会有所帮助:)

答案 1 :(得分:1)

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;

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

答案 2 :(得分:1)

如果两个表中没有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;

希望这可以解决你的问题。