我正在尝试运行查询:
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;
外键是与产品表格的识别关系(Product
。Id
)
基本上我想要完成的是: 1.只要新产品(或以前停用的产品)出现在供应商数据集中,该记录就会在ProductState表中创建为“已激活”。 2.只要产品(已激活)未显示在供应商数据集中,该记录就会在ProductState表中创建为“已停用”。
ProductState表的目的是跟踪产品的激活和停用状态。此外,ProductState是与产品表的多对一关系,产品的状态每天只会更改一次,因此我的PKEY将是ProductId和ChangedDate。
答案 0 :(得分:2)
我认为你应该:
Products
表ProductState
表这将避免任何外键错误,但也会确保您的数据始终准确。您不希望以任何方式“避免”外键约束,InnoDB(我相信您正在使用)永远不会推迟这些约束,除非您完全关闭它们。
同样没有你不能在一个INSERT ... SELECT语句中插入多个表。
答案 1 :(得分:2)
使用外键,你必须先在Product表上获取数据,然后才能进入状态,用这个逻辑思考:“不存在的东西怎么会有状态”?
你应该做的伪代码:
所有这些都应该在一次交易中完成。请注意,除非您确实要删除与其关联的所有信息,否则不应从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