web-dev-qa-db-fra.com

MySQL: Insérer un enregistrement s'il n'existe pas dans la table

J'essaie d'exécuter la requête suivante:

INSERT INTO table_listnames (name, address, tele)
VALUES ('Rupert', 'Somewhere', '022')
WHERE NOT EXISTS (
    SELECT name FROM table_listnames WHERE name='value'
);

Mais cela renvoie une erreur. En gros, je ne veux pas insérer un enregistrement si le champ 'nom' de l'enregistrement existe déjà dans un autre enregistrement - comment vérifier si le nouveau nom est unique?

332
Rupert

En fait, je ne suggère pas que vous fassiez ceci, car l'index UNIQUE tel que suggéré par Piskvor et d'autres est une bien meilleure façon de le faire, mais vous pouvez réellement faire ce que vous tentiez:

CREATE TABLE `table_listnames` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  `address` varchar(255) NOT NULL,
  `tele` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB;

Insérer un enregistrement:

INSERT INTO table_listnames (name, address, tele)
SELECT * FROM (SELECT 'Rupert', 'Somewhere', '022') AS tmp
WHERE NOT EXISTS (
    SELECT name FROM table_listnames WHERE name = 'Rupert'
) LIMIT 1;

Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

SELECT * FROM `table_listnames`;

+----+--------+-----------+------+
| id | name   | address   | tele |
+----+--------+-----------+------+
|  1 | Rupert | Somewhere | 022  |
+----+--------+-----------+------+

Essayez d'insérer le même enregistrement à nouveau:

INSERT INTO table_listnames (name, address, tele)
SELECT * FROM (SELECT 'Rupert', 'Somewhere', '022') AS tmp
WHERE NOT EXISTS (
    SELECT name FROM table_listnames WHERE name = 'Rupert'
) LIMIT 1;

Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

+----+--------+-----------+------+
| id | name   | address   | tele |
+----+--------+-----------+------+
|  1 | Rupert | Somewhere | 022  |
+----+--------+-----------+------+

Insérer un enregistrement différent:

INSERT INTO table_listnames (name, address, tele)
SELECT * FROM (SELECT 'John', 'Doe', '022') AS tmp
WHERE NOT EXISTS (
    SELECT name FROM table_listnames WHERE name = 'John'
) LIMIT 1;

Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

SELECT * FROM `table_listnames`;

+----+--------+-----------+------+
| id | name   | address   | tele |
+----+--------+-----------+------+
|  1 | Rupert | Somewhere | 022  |
|  2 | John   | Doe       | 022  |
+----+--------+-----------+------+

Etc...

429
Mike

INSERT n'autorise pas WHERE dans la syntaxe .

Ce que vous pouvez faire: créez un UNIQUE INDEX sur le champ qui devrait être unique (name), puis utilisez l’une des méthodes suivantes:

  • normal INSERT (et gère l'erreur si le nom existe déjà)
  • INSERT IGNORE (qui sera échouer en silence provoquer un avertissement (au lieu d'erreur) si le nom existe déjà)
  • INSERT ... ON DUPLICATE KEY UPDATE (qui exécutera le UPDATE à la fin si ce nom existe déjà, voir documentation )
271
Piskvor

Travaillé :

INSERT INTO users (full_name, login, password) 
  SELECT 'Mahbub Tito','tito',SHA1('12345') FROM DUAL
WHERE NOT EXISTS 
  (SELECT login FROM users WHERE login='tito');
51
Mahbub Tito

MySQL fournit une solution très mignonne:

REPLACE INTO `table` VALUES (5, 'John', 'Doe', SHA1('password'));

Très facile à utiliser puisque vous avez déclaré une clé primaire unique (ici avec la valeur 5).

26
sdesvergez
INSERT IGNORE INTO `mytable`
SET `field0` = '2',
`field1` = 12345,
`field2` = 12678;

Ici, la requête mysql, qui insère des enregistrements s’il n’existe pas et ignore les enregistrements similaires existants.

----Untested----
18
Montaser El-sawy

Vous pouvez facilement utiliser le moyen suivant:

INSERT INTO ... ON DUPLICATE KEY UPDATE ...

De cette façon, vous pouvez insérer n'importe quel nouvea brut et, si vous avez des données en double, remplacer une colonne spécifique (la meilleure des colonnes est l'horodatage).
Par exemple :

CREATE TABLE IF NOT EXISTS Devices (
  id         INT(6)       NOT NULL AUTO_INCREMENT,
  unique_id  VARCHAR(100) NOT NULL PRIMARY KEY,
  created_at VARCHAR(100) NOT NULL,
  UNIQUE KEY unique_id (unique_id),
  UNIQUE KEY id (id)
)
  CHARACTER SET utf8
  COLLATE utf8_unicode_ci;

INSERT INTO Devices(unique_id, time) 
VALUES('$device_id', '$current_time') 
ON DUPLICATE KEY UPDATE time = '$current_time';
16
Arash Hatami

Si vous ne pouvez vraiment pas obtenir un index unique sur la table, vous pouvez essayer ...

INSERT INTO table_listnames (name, address, tele)
    SELECT 'Rupert', 'Somewhere', '022'
        FROM some_other_table
        WHERE NOT EXISTS (SELECT name
                              FROM table_listnames
                              WHERE name='Rupert')
        LIMIT 1;
12
Brian Hooper

Pour résoudre un problème similaire, j'ai inséré le tableau que je veux insérer dans une colonne unique. En utilisant votre exemple, lors de la création, j'aurais quelque chose comme:

name VARCHAR(20),
UNIQUE (name)

puis utilisez la requête suivante lors de l'insertion:

INSERT IGNORE INTO train
set table_listnames='Rupert'
11
obsessiveCookie

Cette requête fonctionne bien:

INSERT INTO `user` ( `username` , `password` )
    SELECT * FROM (SELECT 'ersks', md5( 'Nepal' )) AS tmp
    WHERE NOT EXISTS (SELECT `username` FROM `user` WHERE `username` = 'ersks' 
    AND `password` = md5( 'Nepal' )) LIMIT 1

Et vous pouvez créer la table en utilisant la requête suivante:

CREATE TABLE IF NOT EXISTS `user` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `username` varchar(30) NOT NULL,
    `password` varchar(32) NOT NULL,
    `status` tinyint(1) DEFAULT '0',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Remarque: créez une table en utilisant la deuxième requête avant d'essayer d'utiliser la première requête.

9
user5505982

Brian Hooper: Vous avez presque atteint votre objectif, mais vous avez une erreur dans votre synatx. Votre insertion ne fonctionnera jamais. J'ai testé sur ma base de données et voici la bonne réponse:

INSERT INTO podatki (datum,ura,meritev1,meritev1_sunki,impulzi1,meritev2,meritev2_sunki,impulzi2)
            SELECT '$datum', '$ura', '$meritve1','$sunki1','$impulzi1','$meritve2','$sunki2','$impulzi2'
                FROM dual
                WHERE NOT EXISTS (SELECT datum,ura
                                      FROM podatki
                                      WHERE datum='$datum' and ura='$ura'

Je vous donne mon exemple de table. Insert est presque identique à celui écrit par Bian Hooper, sauf que je mets la sélection FROM DUAL ont depuis une autre table. Cordialement, Ivan

4
Ivan Laharnar
insert into customer_keyskill(customerID, keySkillID)
select  2,1 from dual
where not exists ( 
    select  customerID  from customer_keyskill 
    where customerID = 2 
    and keySkillID = 1 )
4
Oms G

Vous insérez pas en mettant à jour le résultat. Vous pouvez définir la colonne de nom dans la colonne principale ou la définir comme unique.

3
User 1034

J'ai eu un problème, et la méthode conseillée par Mike a fonctionné en partie, j'ai eu une erreur Dublicate Column name = '0', et j'ai changé la syntaxe de votre requête comme ceci`

     $tQ = "INSERT  INTO names (name_id, surname_id, sum, sum2, sum3,sum4,sum5) 
                SELECT '$name', '$surname', '$sum', '$sum2', '$sum3','$sum4','$sum5' 
FROM DUAL
                WHERE NOT EXISTS (
                SELECT sum FROM names WHERE name_id = '$name' 
AND surname_id = '$surname') LIMIT 1;";

Le problème était avec les noms de colonne. sum3 était égal à sum4 et mysql a lancé les noms de colonnes en double, et j'ai écrit le code dans cette syntaxe et cela a fonctionné à la perfection,

3
Hovhannes Babayan

J'ai eu un problème similaire et je devais en insérer plusieurs, sinon existants. Ainsi, à partir des exemples ci-dessus, je suis venu à cette combinaison ... elle est ici au cas où quelqu'un en aurait besoin.

Remarque: je devais définir le nom partout car MSSQL le demandait ... MySQL fonctionne avec * aussi.

INSERT INTO names (name)
SELECT name
FROM
(
  SELECT name
  FROM
  (
     SELECT 'Test 4' as name
  ) AS tmp_single
  WHERE NOT EXISTS
  (
     SELECT name FROM names WHERE name = 'Test 4'
  )
  UNION ALL
  SELECT name
  FROM
  (
     SELECT 'Test 5' as name
  ) AS tmp_single
  WHERE NOT EXISTS
  (
     SELECT name FROM names WHERE name = 'Test 5'
  )
) tmp_all;

MySQL: CREATE TABLE names (OID int (11) NON NULL AUTO_INCREMENT, name varchar (32) COLLATE utf8_unicode_ci NON NULL, PRIMARY KEY (OID), CLE UNIQUE name_UNIQUE (name) ENGINE =.

ou

MSSQL: CREATE TABLE [noms] ([OID] INT IDENTITY (1, 1) NON NUL, [nom] NVARCHAR (32) NON NUL, CLÉ PRIMAIRE CLUSTERÉE ([OID] ASC)); CREATE UNIQUE NONCLUSTERED INDEX [Nom_nom_index] ON [noms] ([nom] ASC);

2
Waldemar

Cette requête peut être utilisée dans PHP code.

J'ai une colonne ID dans cette table, j'ai donc besoin de vérifier la duplication pour toutes les colonnes sauf cette colonne ID:

#need to change values
SET @goodsType = 1, @sybType=5, @deviceId = asdf12345SDFasdf2345;    


INSERT INTO `devices` (`goodsTypeId`, `goodsId`, `deviceId`) #need to change tablename and columnsnames
SELECT * FROM (SELECT @goodsType, @sybType, @deviceId) AS tmp
WHERE NOT EXISTS (
    SELECT 'goodsTypeId' FROM `devices` #need to change tablename and columns names
    WHERE `goodsTypeId` = @goodsType
        AND `goodsId` = @sybType
        AND `deviceId` = @deviceId
) LIMIT 1;

et maintenant le nouvel élément sera ajouté uniquement s'il n'y a pas de ligne avec des valeurs configurées dans SET string

1
Andrew