MySQL: Tabloda yoksa kayıt ekle


384

Aşağıdaki sorguyu yürütmeye çalışıyorum:

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

Ancak bu bir hata döndürür. Temelde kaydın 'isim' alanı başka bir kayıtta zaten varsa kayıt eklemek istemiyorum - yeni adın benzersiz olup olmadığını nasıl kontrol edebilirim?



12
Bu veya dupes için geçerli tüm cevaplar benzersiz bir dizin ekleyebileceğinizi varsayar. Bazen karar tüm tabloya uygulanamayan iş mantığına dayanır. Örneğin, bir sütunda belirli bir değere sahip birden çok satıra izin verirsiniz, ancak sütundaki başka bir değerin yalnızca bir satırda görünmesine izin verilir. Bunu nasıl başarabiliriz?
Oscar

Yanıtlar:


502

Aslında bunu yapmanızı UNIQUEönermiyorum , çünkü Piskvor ve diğerleri tarafından önerilen indeks bunu yapmak için çok daha iyi bir yol, ama aslında ne denediğinizi yapabilirsiniz:

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;

Bir kayıt ekleyin:

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  |
+----+--------+-----------+------+

Aynı kaydı tekrar eklemeyi deneyin:

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  |
+----+--------+-----------+------+

Farklı bir kayıt ekleyin:

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  |
+----+--------+-----------+------+

Ve bunun gibi...


Güncelleme:

#1060 - Duplicate column nameİki değerin eşit olması durumunda hatayı önlemek için , iç SELECT sütununu adlandırmanız gerekir:

INSERT INTO table_listnames (name, address, tele)
SELECT * FROM (SELECT 'Unknown' AS name, 'Unknown' AS address, '022' AS tele) 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  |
|  2 | John    | Doe       | 022  |
|  3 | Unknown | Unknown   | 022  |
+----+---------+-----------+------+

18
Yardımcı oldu teşekkürler. Asıl sorunum çok daha karmaşık ve sütun benzersiz olamaz ve birincil anahtara güvenemiyorum. Ama tam da aradığım şey buydu.
Rupert

2
@Piskovar: Kabul etti. @Rupert: mümkünse iç seçim deyiminde ( namebu örnekte) belirtilen sütunu dizine eklemelisiniz . Yapabileceğiniz de unutmayın SELECT 'John', 'Doe', '022' FROM table_listnamesyerine, SELECT * FROM (SELECT 'John', 'Doe', '022') AS tmp- ama bu sadece olacak iş eğer table_listnameszaten bir veya daha fazla satır içerir. Hızın farklı olduğundan şüpheliyim, bu yüzden muhtemelen bir endişe değil.
Mike

3
@VijayRamamurthy: Bu, bir Select deyiminin sonucunu eklediğiniz için çalışır. Sorguyu dikkatle okuyun -> WHEREİfade SELECTsorguya aittir . Seçme sorgusu tek bir veri satırı döndürür (veri eklenir) veya hiç veri yoktur (hiçbir şey eklenmez)
Philipp

13
Aynı değeri farklı alanlara iki kez eklemek istiyorsanız (örneğin SELECT 'Humbert', 'Humbert', '1'iç seçimde) bu işe yaramaz . Ben birERROR 1060 (42S21): Duplicate column name
cburgmer

28
@cburgmer Aynı sorunu yaşadım #1060 - Duplicate column name. Bir çözüm buldun mu? Düzenleme: Bulundu. Her bir değerin arkasına AS ekleyin:SELECT * FROM (SELECT 'Rupert' as name, 'Rupert' as friend, '022' as number) AS tmp
Kai Noack

292

INSERT WHEREsözdiziminde izin vermez .

Ne yapabilirsiniz: UNIQUE INDEXbenzersiz ( name) olması gereken bir alan oluşturun ve ardından şunlardan birini kullanın:

  • normal INSERT(ve ad zaten varsa hatayı işleyin)
  • INSERT IGNORE( sessiz bir şekilde başarısız olur ve ad zaten varsa bir uyarıya (hata yerine) neden olur )
  • INSERT ... ON DUPLICATE KEY UPDATE( UPDATEad zaten varsa, sonunda yürütülür, belgelere bakın )

1
uyarı mesajı almanız gerekiyorsa daha sonra yapabilirsinizmysql> show warnings\G
fiorentinoing

2
ime, uyarı mesajı, durumunda INSERT IGNORE, regex ile eşleşir^Duplicate entry '.+' for key '.+'$
user2426679

1
insert ignore kullanırsanız, yinelemeler nedeniyle oluşmayan diğer hataları yoksayar mı?
gepex

1
@gepex Evet, olacak. INSERT IGNOREIMO kullanmakla ilgili büyük bir sorun .
shmosel

1
Not: Benzersiz anahtar kısıtlamasındaki sütunlardan biri boş bırakılabilirse, bu cevap en iyi seçenek olmayabilir! Kısıtlama işe yarıyor, ancak başka sonuçlar da bekleyebilirsiniz. :) ("John Doe", NULL), ("John Doe", NULL), her iki alanın da benzersiz bir anahtar kısıtlaması olmasına rağmen iki satırla sonuçlanır. Ayrıca bkz. Stackoverflow.com/questions/4081783/unique-key-with-nulls
Piemol

57

Çalıştı:

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');

Bu yalnızca Oracle veritabanları için geçerli değil mi? en.wikipedia.org/wiki/DUAL_table Bu soru özellikle MySQL ile ilgilidir!
Son derece Düzensiz

1
Oracle veritabanında test yapmıyorum. MySQL'de iyi çalışıyor ve test edildi.
Mahbub Tito

9
Öğrenilen "ikili" beri MySQL mevcuttur ancak mariadb, MySQL açık kaynak dalında
Çok Düzensiz

3
@ HighlyIrregular'ın wikipedia bağlantısından "Başka birkaç veritabanı (Microsoft SQL Server, MySQL, PostgreSQL, SQLite ve Teradata dahil) herhangi bir tablo gerekmiyorsa FROM yan tümcesini tamamen atlamayı sağlar. Bu, herhangi bir kukla tabloya ihtiyaç duymaz." Aynı sorgu FROM DUAL olmadan MySql'de (bu önemli ise 5.7) çalışıyor gibi görünüyor.
stannius

1
MariaDB'de test edilmiş ve iyi çalışıyor! @MahbubTito
Jeff Monteiro

27

MySQL çok sevimli bir çözüm sunar:

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

Benzersiz bir birincil anahtar (burada 5 değerine sahip) bildirdiğiniz için kullanımı çok kolaydır.


bunu önlemek için benzersiz bir dizin oluşturmanız gerekir, daha fazla bilgi burada: link
Azmeer

Çok tehlikeli. Ne yaptığınızı bilmedikçe girişimde bulunmayın. Aslında, hiç denemeyin. Diğer cevapları kontrol edin.
Jhourlad Estrella

3
Bu, eşleşen tüm satırları SİLECEK ve daha sonra yeniden ekler, aynı davranışın daha güvenli bir sürümü, onları silmek ve yeniden eklemek yerine matematik satırlarını güncelleyen ON DUPLICTE KEY UPDATE kullanmaktır: dev.mysql.com/doc/ refman / 5.7 / tr /
replace.html

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

Burada mysql sorgusu, yoksa kayıtları ekler ve mevcut benzer kayıtları yoksayar.

----Untested----

4
benim için çalışmadı, IGNORE INE emAssignedTagsForEvent SET eventId = '2', defaultTagId = '1';
pitu

8
Ekleme ve güncelleme sözdizimlerinin bir karışımı gibi görünüyor. Bunu mu demek istediniz INSERT IGNORE INTO `mytable` (`field0`, `field1`, `field2`) values ('2', 12345, 12678);?
Hobo

@Hobo MySQL El Kitabından dev.mysql.com/doc/refman/5.7/en/insert.html INSERT sözdizimi: INSERT [...] IGNORE INTO mytable VALUES ...Veya olabilirINSERT [...] IGNORE INTO mytable SET col_name={expr | DEFAULT},...
Shirkam

"IGNORE değiştiricisini kullanırsanız, INSERT deyimi yürütülürken oluşan hatalar yok sayılır." Yani temelde hiçbir şey çözmediniz.
Marcelo Agimóvel

18

Aşağıdaki yolu kolayca kullanabilirsiniz:

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

Bu şekilde yeni ham öğeler ekleyebilirsiniz ve yinelenen verileriniz varsa, belirli sütunu değiştirin (en iyi sütunlar zaman damgalarıdır).
Örneğin :

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';

13

Tabloda gerçekten benzersiz bir dizin alamıyorsanız, deneyebilirsiniz ...

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

Benzer bir sorunun üstesinden gelmek için, tabloyu benzersiz bir sütuna sahip olacak şekilde değiştirdim. Örneğini kullanarak, yaratılışta şöyle bir şey olurdu:

name VARCHAR(20),
UNIQUE (name)

ve içine eklerken aşağıdaki sorguyu kullanın:

INSERT IGNORE INTO train
set table_listnames='Rupert'

Bu çözümü tercih ederim.
Ilyas karim

9

Bu sorgu iyi çalışıyor:

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

Ve aşağıdaki sorguyu kullanarak tablo oluşturabilirsiniz:

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 ;

Not: İlk sorguyu kullanmaya çalışmadan önce ikinci sorguyu kullanarak tablo oluşturun.


md5 şifre karması .... evet!
Chad Grant

4

Brian Hooper: Neredeyse noktayı vuruyorsunuz ancak sözdiziminizde bir hata var. Eklemeniz asla çalışmaz. Veritabanımda test ettim ve işte doğru cevap:

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'

Size y tablosu örneğimi veriyorum. Insert, Bian Hooper'ın yazdığı gibi neredeyse aynıdır, ancak diğer tablodan DUAL DUAL'i seçmem dışında. Saygılarımla, Ivan


2
Bu "ikili" nedir? Dahili bir anahtar kelime mi? Brian'ın söylediklerinden farkı görmüyorum ... EDIT: Daha fazla soruşturma karışık ve çelişkili (?) Sonuçlar aldı. İken , SQL ÇİFT tablo sayfası MySQL ÇİFT tabloları desteklemediğini söylüyor, MySQL manuel öyle söylüyor. Kendi testim, unknown table status: TABLE_TYPEmesaj verdiğinden, sorgunun bir sonuç vermesine rağmen, bunu yapmadığını gösteriyor . Muhtemelen MySQL FROM DUALfıkra gerektirmediği için mi?
not2qubit

4
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 )

dual, MySQL değil bir Oracle tablosu
Çok Düzensiz

3

Sonucu güncellemiyor ekliyorsunuz. Birincil sütunda ad sütununu tanımlayabilir veya benzersiz olarak ayarlayabilirsiniz.


3

Bir sorunum vardı ve Mike'ın önerdiği yöntem kısmen çalıştı, bir hata Dublicate Column name = '0' vardı ve sorgunuzun sözdizimini şu şekilde değiştirdim `

     $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;";

Sorun sütun adlarındaydı. sum3 sum4'e eşitti ve mysql genel sütun adlarını attı ve kodu bu sözdiziminde yazdım ve mükemmel çalıştı,


1
DUAL'in sahibi SYS'dir (SYS veri sözlüğüne sahiptir, bu nedenle DUAL veri sözlüğünün bir parçasıdır.) Ancak DUAL'e herhangi bir kullanıcı tarafından erişilebilir. Tabloda DUMMY adı verilen ve 'X' değerine sahip tek bir VARCHAR2 (1) sütunu vardır. MySQL, DUAL'in herhangi bir tablodan veriye ihtiyaç duymayan sorgularda bir tablo olarak belirtilmesine izin verir. DUAL tablosu, Oracle ve diğer veritabanı kurulumlarında varsayılan olarak bulunan özel bir tek satırlık, tek sütunlu bir tablodur. Oracle'da, tabloda 'X' değerine sahip DUMMY adlı tek bir VARCHAR2 (1) sütunu vardır. SYSDATE veya USER gibi bir sahte sütun seçilmesinde kullanılmaya uygundur.
Adnan haider

3

Benzer bir sorunum vardı ve yoksa birden fazla eklemek gerekiyordu. Bu yüzden yukarıdaki örneklerden bu kombinasyona geldim ... birinin ihtiyaç duyması ihtimaline karşı burada.

Uyarı: MSSQL'in gerektirdiği gibi her yerde isim tanımlamak zorunda kaldım ... MySQL de * ile çalışıyor.

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( OIDint (11) NOT NULL AUTO_INCREMENT, namevarchar (32) COLLATE utf8_unicode_ci BOŞ DEĞİL, PRIMARY KEY ( OID), BENZERSİZ ANAHTAR name_UNIQUE( name)) ENGINE = InnoDB AUTO_INCREMENT = 1;

veya

MSSQL: TABLO OLUŞTUR [adlar] ([OID] INT IDENTITY (1, 1) BOŞ DEĞİL, [isim] NVARCHAR (32) BOŞ DEĞİL, İLK ANAHTAR KÜMELENMİŞ ([OID] ASC)); EŞSİZ OLMAYAN ENDEKS OLUŞTUR [Dizin_Adları_Adı] AÇIK [adlar] ([ad] ASC);


2

Bu sorgu PHP kodunda kullanılabilir.

Bu tabloda bir kimlik sütunu var, bu yüzden bu kimlik sütunu hariç tüm sütunlar için çoğaltma için kontrol gerekir:

#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;

ve şimdi yeni öğe yalnızca SETdizede yapılandırılmış değerlere sahip satır yoksa eklenir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.