由于外键约束导致插入延迟

时间:2011-05-11 16:28:42

标签: mysql insert foreign-keys delay

我正在尝试运行查询:

INSERT
  INTO `ProductState` (`ProductId`, `ChangedOn`, `State`)
SELECT t.`ProductId`, t.`ProcessedOn`, \'Activated\'
  FROM `tmpImport` t
  LEFT JOIN `Product` p
    ON t.`ProductId` = p.`Id`
 WHERE p.`Id` IS NULL
    ON DUPLICATE KEY UPDATE
       `ChangedOn` = VALUES(`ChangedOn`)

(我不太确定查询是否正确,但似乎有效),但是我遇到了以下问题。我在创建“Products”表中的条目之前运行此查询,并且由于条目尚未在Products表中而导致出现外键约束问题。

我的问题是,有没有办法运行此查询,但在执行上述查询的插入部分之前,请等到下一个查询(更新Product表)?另外需要注意的是,如果在创建Product条目后运行查询,它将不再将p。Id视为null并因此失败,因此必须在创建Product条目之前执行它。

--->编辑< --- 我想要实现的概念如下: 对于初学者,我将一组数据导入临时表,Product表是通过临时表中的数据集添加的(或过去的)所有产品的列表。我需要的是一个单独的表,它提供产品的状态更改,因为有时产品将不可用(不再在供应商提供的数据集中)。

ProductState表如下:

CREATE  TABLE IF NOT EXISTS `ProductState` (
  `ProductId` VARCHAR(32) NOT NULL ,
  `ChangedOn` DATE NOT NULL ,
  `State` ENUM('Activated','Deactivated') NULL ,
  PRIMARY KEY (`ProductId`, `ChangedOn`) ,
  INDEX `fk_ProductState_Product` (`ProductId` ASC) ,
  CONSTRAINT `fk_ProductState_Product`
    FOREIGN KEY (`ProductId` )
    REFERENCES `Product` (`Id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci;

外键是与产品表格的识别关系(ProductId

基本上我想要完成的是: 1.只要新产品(或以前停用的产品)出现在供应商数据集中,该记录就会在ProductState表中创建为“已激活”。 2.只要产品(已激活)未显示在供应商数据集中,该记录就会在ProductState表中创建为“已停用”。

ProductState表的目的是跟踪产品的激活和停用状态。此外,ProductState是与产品表的多对一关系,产品的状态每天只会更改一次,因此我的PKEY将是ProductId和ChangedDate。

2 个答案:

答案 0 :(得分:2)

我认为你应该:

  • 开始交易
  • 将您的插入插入Products
  • 将您的插入插入ProductState
  • 提交交易

这将避免任何外键错误,但也会确保您的数据始终准确。您不希望以任何方式“避免”外键约束,InnoDB(我相信您正在使用)永远不会推迟这些约束,除非您完全关闭它们。

同样没有你不能在一个INSERT ... SELECT语句中插入多个表。

答案 1 :(得分:2)

使用外键,你必须先在Product表上获取数据,然后才能进入状态,用这个逻辑思考:“不存在的东西怎么会有状态”?

你应该做的伪代码:

  1. 请阅读供应商的产品列表
  2. 将它们与Product表中的现有列表进行比较
  3. 如果找到新的:3.1将其插入到产品表中,3.2将其插入到ProductState表
  4. 如果供应商列表中缺少:4.1将其插入ProductState表
  5. 所有这些都应该在一次交易中完成。请注意,除非您确实要删除与其关联的所有信息,否则不应从Product表中删除内容。还删除您存储的所有“状态”。

    不是试图在1个查询中全部执行此操作 - 最好的办法是创建一个存储过程,按照上面的步骤进行操作。我认为在1次查询中完成所有操作过于复杂(或者在这种情况下,可能是不可能的)。

    编辑:这样的事情:

    CREATE PROCEDURE `some_procedure_name` ()
    BEGIN
    
    -- Breakdown the tmpImport table to 2 tables: new and removed
    SELECT * INTO _temp_new_products
    FROM`tmpImport` t
    LEFT JOIN `Product` p
    ON t.`ProductId` = p.`Id`
    WHERE p.`Id` IS NULL
    
    SELECT * INTO _temp_removed_products
    FROM `Product` p
    LEFT JOIN `tmpImport` t 
    ON t.`ProductId` = p.`Id`
    WHERE t.`ProductId` IS NULL
    
    -- For each entry in _temp_new_products:
    -- 1. Insert into Product table
    -- 2. Insert into ProductState table 'activated'
    
    -- For each entry in _temp_removed_products:
    -- 1. Insert into ProductState table 'deactivated'
    
    -- drop the temporary tables
    DROP TABLE _temp_new_products
    DROP TABLE _temp_removed_products
    END