MySQL nasıl 'var değilse eklemek' için?

7 Cevap php

Googling tarafından başlatılan ve muteksi tablolar bahsediyor bu article bulundu.

I ~ 14 milyon kayıtlarında bir tablo var. Ben aynı formatta daha fazla veri eklemek istiyorsanız, eklemek için bir sorgu çift (kontrol etmek yani, bir sorgu ve birini kullanarak olmadan zaten yok ben eklemek istediğiniz kaydı sağlamak için bir yol sonuç kümesi orada olduğunu Boş)?

Bir alana bir unique kısıtlama zaten orada eğer insert başarısız garanti mı?

Ben php aracılığıyla yuvasını kesilirken merely bir kısıtlama ile, komut croaks gibi görünüyor.

7 Cevap

kullanmak INSERT IGNORE INTO table

bkz http://bogdan.org.ua/2007/10/18/mysql-insert-if-not-exists-syntax.html

INSERT … ON DUPLICATE KEY UPDATE sözdizimi de var, sen dev.mysql.com ile ilgili açıklamalar bulabilirsiniz


Post from bogdan.org.ua according to Google's webcache:

18 Ekim 2007

Başlatmak için: son MySQL gibi, başlığında sunulan sözdizimi mümkün değildir. Ancak mevcut işlevselliğini kullanarak bekleniyor ne başarmak için birkaç çok kolay bir yolu vardır.

INSERT, IGNORE DEĞİŞTİR veya INSERT kullanan ... YİNELENEN KEY UPDATE: 3 olası çözümleri vardır.

Biz bir tablo var düşünün:

CREATE TABLE `transcripts` (
`ensembl_transcript_id` varchar(20) NOT NULL,
`transcript_chrom_start` int(10) unsigned NOT NULL,
`transcript_chrom_end` int(10) unsigned NOT NULL,
PRIMARY KEY (`ensembl_transcript_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Şimdi nedeniyle boru hattı yürütmenin herhangi bir aşamada kırılmış olabilir, çeşitli nedenlerle bir otomatik Ensembl transkript meta-veri alma boru hattı, ve o olduğunu düşünün. Böylece, iki şeyi sağlamak gerekir: 1) boru hattının tekrarlanan infazlar bizim veritabanı yok olmaz, ve 2) tekrarlanan infazlar nedeniyle 'yinelenen birincil anahtar' hataları ölmeyecek.

Yöntem 1: DEĞİŞTİR kullanarak

Çok basit:

REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = ‘ENSORGT00000000001′,
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;

If the record exists, it will be overwritten; if it does not yet exist, it will be created. However, using this method isn’t efficient for our case: we do not need to overwrite existing records, it’s fine just to skip them.

Method 2: using INSERT IGNORE Also very simple:

INSERT IGNORE INTO `transcripts`
SET `ensembl_transcript_id` = ‘ENSORGT00000000001′,
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;

'Ensembl_transcript_id' zaten veritabanında mevcut ise burada, sessizce (göz ardı) atlanır olacaktır. (Daha kesin olmak gerekirse, burada MySQL başvuru kitabında bir alıntı: "Eğer IGNORE anahtar kelime kullanırsanız, INSERT deyimi yürütülürken oluşan hatalar Örneğin, mevcut bir UNIQUE dizini çoğaltan bir satır, IGNORE olmadan yerine uyarı olarak kabul edilir. veya tabloda PRIMARY KEY değer bir yinelenen anahtar hata neden olur ve deyim iptal edilir. "). kayıt henüz yoksa, yaratılacaktır.

Bu ikinci yöntem, diğer herhangi bir sorun (kılavuzuna bakın) oluşması durumunda sorgu olmayan kürtaj dahil olmak üzere birçok potansiyel zayıflıkları vardır. Daha önce IGNORE anahtar sözcüğü olmadan test eğer Böylece kullanılmalıdır.

Orada bir daha seçenek: INSERT kullanmak YİNELENEN KEY UPDATE sözdizimi ON ... ve UPDATE bölümünde sadece bir şey yapmak 0 0 hesaplanması gibi bazı anlamsız (boş) işlemini yapın (Geoffray MySQL optimizasyonu için id = id atama yapıyor anlaşılacağı ) bu operasyonu görmezden motor. Bu yöntemin avantajı, sadece yinelenen anahtar olayları sayar, ve hala diğer hataları durdurur olmasıdır.

Son bir haber olarak: bu yazı Xaprb esinlenilmiştir. Ben de esnek SQL sorguları yazarken onun diğer yazı danışmak tavsiye ediyorum.

on duplicate key update, ya da insert ignore MySQL ile uygulanabilir çözümler olabilir.

Bir istisna kabul edilebilir olup olmadığını herhangi bir basit kısıtlama, iş yapmak gerekir. Örnekler:

  • Birincil anahtar vekaleten değilse
  • bir sütun üzerinde benzersiz kısıtlama
  • çoklu-sütun benzersiz kısıtlama

Maalesef bu aldatıcı basit görünüyor olmasıdır. Ben bunu bizimle paylaşmak bağlantıya karşı karşıya kötü göründüğünü biliyorum. ;-(

Bu ihtiyacı doldurmak gibi görünüyor, çünkü Ama bu cevap vermek neverleless. (Eğer değilse, "İyi Bir Şey" (TM) da olurdu, sizin ihtiyaçlarınızı güncellenmesi tetikleyebilir).

Edited: bir ekleme veritabanı benzersiz kısıtlamayı kıracak olursa, bir istisna sürücüsü tarafından geçirilen veritabanı düzeyinde atmak olduğunu. Bu kesinlikle bir başarısızlık ile, sizin komut durur. O davayı hitap PHP mümkün olmalı ...

İşte tüm belirtilen sütun değerleri zaten tabloda mevcut olmayan sadece bir satır eklemek bir PHP işlevi olduğunu.

Sütun bir farklılık, satır eklenecektir.

Tablo boş ise, satır eklenecektir.

Belirtilen tüm sütunları belirtilen değerlere sahip olduğu bir satır varsa, satır eklenecektir olmayacaktır.

function insert_unique($table, $vars)
{
  if (count($vars))
  {
    $table = mysql_real_escape_string($table);
    $vars = array_map('mysql_real_escape_string', $vars);

    $req = "INSERT INTO `$table` (`". join('`, `', array_keys($vars)) ."`) ";
    $req .= "SELECT '". join("', '", $vars) ."' FROM DUAL ";
    $req .= "WHERE NOT EXISTS (SELECT 1 FROM `$table` WHERE ";

    foreach ($vars AS $col => $val)
      $req .= "`$col`='$val' AND ";

    $req = substr($req, 0, -5) . ") LIMIT 1";

    $res = mysql_query($req) OR die();
    return mysql_insert_id();
  }

  return False;
}

Örnek kullanım:

<?php
insert_unique('mytable', array(
  'mycolumn1' = 'myvalue1',
  'mycolumn2' = 'myvalue2',
  'mycolumn3' = 'myvalue3'
  )
);
?>

Aşağıdaki deneyin:

IF (SELECT COUNT(*) FROM beta WHERE name = 'John' > 0)
  UPDATE alfa SET c1=(SELECT id FROM beta WHERE name = 'John')
ELSE
BEGIN
  INSERT INTO beta (name) VALUES ('John')
  INSERT INTO alfa (c1) VALUES (LAST_INSERT_ID())
END
REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;

Kayıt varsa, bunun üzerine yazılır; henüz yoksa, yaratılacaktır.