【问题标题】:Conditional insert based on LAST_INSERT_ID基于 LAST_INSERT_ID 的条件插入
【发布时间】:2014-09-18 19:45:23
【问题描述】:

here 使用 IF 语句问了一个几乎相同的问题,但他没有得到可操作的答案,只是建议去here 那里没有使用 IF 语句。我尝试使用后一个链接编写 IF 语句和条件语句,但我被卡住了(见下文)。

我希望只有在前一次插入尝试实际插入一行时才能有条件地插入一行 (ROW_COUNT > 0)。之前的插入可能是重复数据,所以我故意将其设置为 LAST_INSERT_ID 为空,这样LAST_INSERT_ID 就不会发生后续的子插入。 SQL 脚本是由 C# 脚本创建的,因此LAST_INSERT_ID 很可能没有指向您期望的位置。

这是一个非常小的脚本生成代码示例(最终数据库中有大约 300 万行):

SET @Vendors_Vendor_ID = (SELECT vendor_ID FROM VENDORS WHERE vendorName = 'PCA');
INSERT IGNORE INTO PCBID (PCBID, PCBDrawing, AssemblyDrawing, PONumber, Vendors_Vendor_ID) 
VALUES (11001, '10405', '41606', '091557.5', @Vendors_Vendor_ID);
SET @eventType_ID = (SELECT EVENTTYPE_ID FROM EVENTTYPES WHERE EVENTTYPE = 'Creation');
SET @USER = 'CTHOMAS';
INSERT IGNORE INTO EVENTS (PCBID, EVENTTYPE_ID, DATETIME, USER) 
VALUES (11001, @eventType_ID, '2009-06-15T13:15:27', @USER);
SET @EVENT_ID = IF(ROW_COUNT() > 0, LAST_INSERT_ID(), null);
-- THIS DOES NOT WORK
SELECT IF(@EVENT_ID != null, 
    INSERT INTO EVENTDETAILS (EVENT_ID, ITEMNAME, ITEMVALUE) 
    VALUES (@EVENT_ID, 'Notes', 'WO#89574'), 
    null);

-- THIS DOESN'T WORK EITHER
INSERT INTO EVENTDETAILS (EVENT_ID, ITEMNAME, ITEMVALUE)
SELECT @EVENT_ID, 'Notes', 'WO#89574'
WHERE @EVENT_ID != null;

PCBID表不存在重复数据问题,Events表有复合唯一键,通过INSERT IGNORE防止重复数据:

CREATE  TABLE IF NOT EXISTS `uniqueTest`.`events` (
`Event_ID` INT(11) NOT NULL AUTO_INCREMENT ,
`PCBID` INT(11) NOT NULL ,
`EventType_ID` INT(11) NOT NULL ,
`DateTime` DATETIME NOT NULL ,
`User` VARCHAR(45) NOT NULL ,
PRIMARY KEY (`Event_ID`) ,
UNIQUE KEY `PDU_Index` (`PCBID`, `DateTime`, `User`),

问题: 我需要能够根据之前对 Events 表的插入尝试进行条件插入,如果它被忽略(因为它是重复数据),也不要插入任何子行。目前没有办法使任何EventDetail 数据唯一,可能存在基于给定Event_ID 的多行合法数据。

Events 表下面可能有四个更深的级别,具体取决于它是什么类型的数据,如果事件数据因为重复数据而没有被插入,那么也不会写入子数据(因为它会重复为好)。

【问题讨论】:

  • 您可以使用 AFTER INSERT 触发器,并忽略忽略。如果您有重复的键条目,则插入将失败并且不会执行触发器。

标签: mysql


【解决方案1】:

您的第二次尝试几乎是正确的。您必须使用 IS NOT NULL 检查 NULL 值。所以使用

INSERT INTO EVENTDETAILS (EVENT_ID, ITEMNAME, ITEMVALUE)
SELECT @EVENT_ID, 'Notes', 'WO#89574' FROM DUAL
WHERE @EVENT_ID IS NOT NULL;  -- instead of != 

INSERT INTO EVENTDETAILS (EVENT_ID, ITEMNAME, ITEMVALUE)
SELECT t.* FROM (
    SELECT @EVENT_ID, 'Notes', 'WO#89574'
) t
WHERE @EVENT_ID IS NOT NULL;  -- instead of != 

第一个不行:

-- THIS DOES NOT WORK
SELECT IF(@EVENT_ID != null, 
    INSERT INTO EVENTDETAILS (EVENT_ID, ITEMNAME, ITEMVALUE) ...

因为IF的语法是

IF(expr1,expr2,expr3)

如果 expr1 为 TRUE(expr1 0 且 expr1 NULL),则 IF() 返回 expr2;否则返回 expr3。 IF() 返回一个数字或字符串值,具体取决于使用它的上下文。

语句的条件执行只能在stored routines 中进行。存储例程的IF syntax 将允许类似

IF @EVENT_ID IS NOT NULL THEN
    INSERT INTO EVENTDETAILS (EVENT_ID, ITEMNAME, ITEMVALUE) ...
END IF

你必须区分这两个语法版本。

【讨论】:

  • 感谢您的帮助,非常感谢。使用上面的示例,我在 WHERE 子句中收到:“语法错误,意外 WHERE,期待 END_OF_INPUT 或 ';'”。
  • @delliottg 糟糕,我阅读的不够仔细。如果你使用WHERE 子句,你也必须有一个FROM 子句。您可以使用从 Oracle 借来的 FROM DUAL 或使用子选择。两者都在我的编辑中指出。
  • 不用担心。我不得不将 WHERE 子句之前的“a”更改为“t”,这使它完美地工作,谢谢!你可以用它来编辑你的答案吗?它不会让我做出那么小的改变。
  • @delliottg 已完成。我的测试查询确实使用了别名a,但是当我编辑我的答案时,我发现t 更方便(temp 的缩写),但没有彻底纠正它。最好能修正这些错别字。很高兴能为您提供帮助,您的问题已解决。
  • 再次感谢,您为我节省了数小时和数小时的工作时间。
猜你喜欢
  • 2014-04-22
  • 1970-01-01
  • 2018-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
相关资源
最近更新 更多