2017-02-19 3 views
0

J'ai le problème suivant: Chaque auteur a un nom et n-alias pour ce nom. Chaque alias provient d'une source. Chaque alias a m sources. Par exempleMySQL ON DUPLICATE insérer dans une autre table

AUTHOR| ALIAS | SOURCE 
------------------------- 
Will| Willy |George 
Will| Bill | Jenny 
William| Will| Francis 
William| Bill| Maya 

J'ai une table pour l'auteur et son nom, un pour tous ses alias:

CREATE TABLE alias (
    authors_id INT NOT NULL, 
    alias VARCHAR(150) NOT NULL, 
    id INT NOT NULL AUTO_INCREMENT 
    PRIMARY KEY (author_id,alias); 

id sert de clé étrangère. est ici la deuxième table pour les sources

CREATE TABLE alias_source (
    id INT NOT NULL AUTO_INCREMENT 
    source VARCHAR(150) NOT NULL, 
    alias_id INT NOT NULL, 
    PRIMARY KEY (id) 
    FOREIGN KEY (alias_id) REFERENCES alias(id); 

Maintenant, je dois une déclaration pour insérer MySQL lors de l'insertion auteur , alias, source dans alias que la source est insérée dans alias_source. Et sur l'alias en double non seulement une nouvelle source est ajoutée.

Répondre

0

Une instruction INSERT dans SQL peut uniquement être insérée dans une table et ne peut répertorier que les colonnes de cette table. Vous ne pouvez pas inclure votre colonne source dans l'instruction INSERT, car ce n'est pas une colonne de la table alias. Les déclencheurs peuvent vous permettre d'insérer dans une table secondaire, mais le déclencheur doit connaître la valeur à insérer. Dans ce cas, le déclencheur n'a aucun moyen d'obtenir la valeur pour source.

Cette tâche est beaucoup plus facile à faire avec deux instructions INSERT.

INSERT IGNORE INTO alias SET author_id = ?, alias = ?; 
INSERT INTO alias_source ... 

Mais vous avez un problème parce que votre table alias a une colonne auto-incrément id, mais cette colonne ne fait pas partie d'une clé. Dans InnoDB, vous devez faire de la colonne auto-incrément la première colonne d'une clé.

Votre table alias_source a une clé étrangère faisant référence à alias(id) mais ce n'est pas autorisé. Une clé étrangère doit référencer une clé de la table parent. Il doit référencer la clé unique ou primaire et référencer toutes les colonnes de la clé (sinon, vous obtenez une ligne dans une table enfant qui peut faire référence à plusieurs lignes dans la table parent, ce qui n'a aucun sens).

Si vous souhaitez utiliser une colonne à incrémentation automatique pour votre table alias, définissez-la comme clé primaire et attribuez une contrainte UNIQUE secondaire aux autres colonnes.

CREATE TABLE alias (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    authors_id INT NOT NULL, 
    alias VARCHAR(150) NOT NULL, 
    UNIQUE KEY (author_id,alias)); 

Ensuite, interrogez le id après l'insertion. Si vous avez inséré une nouvelle ligne, ou si la ligne existait déjà, vous obtiendrez le id pour la ligne avec l'auteur et l'alias choisis.

INSERT IGNORE INTO alias SET author_id = ?, alias = ?; 
SELECT id FROM alias WHERE author_id = ? AND alias = ? INTO @id; 
INSERT INTO alias_source SET alias_id = @id, source = ?; 

Re votre question dans le commentaire suivi:

Bonne idée, mais il ne fonctionne pas comme vous pensez. Vous pouvez faire un ensemble factice de id=id et définir une variable de session comme effet secondaire.

mysql> insert into alias set author_id=1, alias='alias' 
    on duplicate key update id = @id:=id; 

mysql> select @id; 
+------+ 
| @id | 
+------+ 
| NULL | 
+------+ 

Mais pourquoi n'a-t-il pas défini la variable de session sur l'ID?Parce que cet insert était pas une copie, il s'agissait d'une nouvelle ligne. La valeur id n'avait donc pas encore été générée par auto-incrémentation au moment où l'IODKU était exécutée.

Si vous faites ensuite la même IODKU pour une ligne qui est un double, la valeur id a déjà été ajouté à la ligne, de sorte que vous obtenez la valeur dans l'effet secondaire:

mysql> insert into alias set author_id=1, alias='alias' 
    on duplicate key update id = @id:=id; 

mysql> select @id; 
+------+ 
| @id | 
+------+ 
| 1 | 
+------+ 

Donc, vous devrez écrire le code de l'application de toute façon pour vérifier si @id est NULL ou non, et faire une requête SELECT id si @id est NULL.

Cela semble plus compliqué que de simplement faire le SELECT id comme une action standard après le INSERT IGNORE comme je l'ai montré ci-dessus.

+0

Merci pour la réponse @ facture! Mais est-il possible d'utiliser ON DUPLICATE KEY et de stocker l'ID dupliqué dans @id? Passer la deuxième déclaration? –