Reputation: 1292
I have two MySQL tables and I need to insert a record in each of them. Caveat: The insert into dependable table may fail due to duplicate key conflict. In that case none of the rows should be inserted.
CREATE TABLE `meanings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `aliases` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`meaningId` int(10) unsigned DEFAULT NULL,
`phrase` varchar(8) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `phrase_UNIQUE` (`phrase`),
KEY `meaning_IDX` (`meaningId`),
CONSTRAINT `fk_Synonyms_1` FOREIGN KEY (`meaningId`) REFERENCES `meanings` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
In a nutshell I need to do following but faster:
INSERT IGNORE INTO aliases (phrase, meaningId) VALUES ('word1', NULL);
SELECT IF(row_count() > 0, last_insert_id(), 0) INTO @aliasId;
INSERT INTO meanings (id) SELECT null FROM aliases WHERE id=@aliasId;
SELECT IFNULL(last_insert_id(), 0) INTO @meaningId;
UPDATE aliases SET meaningId=@meaningId WHERE id=@aliasId;
My constraints/conditions/wishes:
DELETE FROM meanings
My thoughts:
trigger after insert
on aliases
that inserts a row into meanings
and updates back inserted row's aliases.meaningId
but I am worried about performanceQUESTION: What is the fastest solution to insert ~40 (possibly conflicting) records into aliases
at the time with corresponding records in meaning
table?
It seems that this use case scenario is so common that something back in my head keeps saying that I might lack some knowledge of existing trivial solutions/inbuilt support for this particular case that is both more elegant and more efficient (then the solution I came up with bellow).
Note: The table is really 1:n even though in this example it behaves strictly 1:1. In my use case the data start their life cycle as 1:1 but later on their meaning
can change...
The example of desired result
Before insert:
SELECT * FROM meanings;
# id
1
2
3
SELECT meaningId, phrase FROM aliases;
# meaningId phrase
1 word1
2 word2
3 word3
Now I need to insert in highly optimized way values word3
(note this one already exists), word4
, word5
so the result is this:
SELECT * FROM meanings;
# id
1
2
3
4
5
SELECT meaningId, phrase FROM aliases;
# meaningId phrase
1 word1
2 word2
3 word3
4 word4
5 word5
Upvotes: 0
Views: 34
Reputation: 1292
The best way I could come up with given all the circumstances and constraints is this:
ALTER TABLE `meanings`
ADD COLUMN `initialAliasId` INT(10) UNSIGNED DEFAULT NULL,
ADD UNIQUE INDEX `initialAliasId_UNIQUE` (`initialAliasId` ASC);
INSERT IGNORE INTO aliases (phrase) VALUES ('word1'), ('word2'), ('word3');
INSERT IGNORE INTO meanings (initialAliasId) SELECT id FROM aliases WHERE meaningId IS NULL;
UPDATE aliases as a LEFT JOIN meanings as m ON (m.initialAliasId = a.id)
SET a.meaningId = m.id WHERE a.meaningId IS NULL;
Upvotes: 0