SQL insérer dans la table seulement si l'enregistrement n'existe pas [dupliquer]

cette question a déjà une réponse ici:

  • vérifier si une rangée existe, sinon inscrire 11 réponses
  • MySQL Conditionnelle Insérer 12 réponses

je veux exécuter un ensemble de requêtes pour insérer des données dans une table SQL, mais seulement si l'enregistrement satisfaisant certains critères sont respectés. Le tableau comporte 4 champs: id (primaire), fund_id , date et price

j'ai 3 champs dans la requête: fund_id , date et price .

Donc ma requête serait quelque chose comme ceci:

INSERT INTO funds (fund_id, date, price)
    VALUES (23, '2013-02-12', 22.43)
    WHERE NOT EXISTS (
       SELECT * 
       FROM funds 
       WHERE fund_id = 23
         AND date = '2013-02-12'
    );

Donc Je ne veulent insérer les données que si un enregistrement correspondant aux fund_id et date n'existe pas déjà. Si ce qui précède est correct, il me semble que c'est un moyen tout à fait inefficace de réaliser ceci puisqu'une instruction select supplémentaire doit être exécutée à chaque fois.

y a-t-il une meilleure façon d'atteindre ce qui précède?

modifier: à des fins de clarification, ni fund_id ni date ne sont des champs uniques; les enregistrements partageant le même fund_id ou la même date n'existeront pas. l'enregistrement devrait avoir à la fois le même nom_de_fonds et la même date qu'un autre.

60
demandé sur harryg 2013-05-09 15:12:16

3 réponses

cela pourrait être une solution simple pour atteindre cet objectif:

INSERT INTO funds (ID, date, price)
SELECT 23, DATE('2013-02-12'), 22.5
  FROM dual
 WHERE NOT EXISTS (SELECT 1 
                     FROM funds 
                    WHERE ID = 23
                      AND date = DATE('2013-02-12'));

p. S. alternativement (si ID est une clé primaire):

 INSERT INTO funds (ID, date, price)
    VALUES (23, DATE('2013-02-12'), 22.5)
        ON DUPLICATE KEY UPDATE ID = 23; -- or whatever you need

voir ce violon .

50
répondu Trinimon 2013-05-09 12:37:15

bien que la réponse que j'ai initialement indiquée comme étant choisie soit correcte et qu'elle permette d'obtenir ce que j'ai demandé, il y a une meilleure façon de le faire (ce que d'autres ont reconnu mais n'ont pas fait). Un indice composite unique doit être créé sur la table comprenant fund_id et date .

ALTER TABLE funds ADD UNIQUE KEY `fund_date` (`fund_id`, `date`);

, Puis lors de l'insertion d'un enregistrement d'ajouter la condition lorsqu'un conflit est détecté:

INSERT INTO funds (`fund_id`, `date`, `price`)
    VALUES (23, DATE('2013-02-12'), 22.5)
        ON DUPLICATE KEY UPDATE `price` = `price`; --this keeps the price what it was (no change to the table) or:

INSERT INTO funds (`fund_id`, `date`, `price`)
    VALUES (23, DATE('2013-02-12'), 22.5)
        ON DUPLICATE KEY UPDATE `price` = 22.5; --this updates the price to the new value

cela fournira une bien meilleure performance à un sous-requête et la structure de la table est supérieure. Il vient avec la mise en garde que vous ne pouvez pas avoir des valeurs nulles dans vos colonnes de clés uniques car ils sont encore traités comme des valeurs par MySQL.

39
répondu harryg 2013-11-13 11:12:03

en supposant que vous ne pouvez pas modifier DDL (pour créer une contrainte unique) ou sont limités à être en mesure d'écrire DML puis de vérifier un résultat null sur filtré de vos valeurs par rapport à l'ensemble de la table

VIOLON

insert into funds (ID, date, price) 
select 
    T.* 
from 
    (select 23 ID,  '2013-02-12' date,  22.43 price) T  
        left join 
    funds on funds.ID = T.ID and funds.date = T.date
where 
    funds.ID is null
4
répondu gillyspy 2013-05-09 11:37:23