วิธีการ 'แทรกถ้าไม่มี' ใน MySQL?


838

ฉันเริ่มโดย googling และพบบทความนี้ที่พูดถึงตาราง mutex

ฉันมีตารางที่มีประมาณ 14 ล้านเร็กคอร์ด หากฉันต้องการเพิ่มข้อมูลเพิ่มเติมในรูปแบบเดียวกันมีวิธีที่จะทำให้แน่ใจว่าระเบียนที่ฉันต้องการแทรกไม่มีอยู่แล้วโดยไม่ใช้คู่ของแบบสอบถาม (เช่นแบบสอบถามหนึ่งแบบสอบถามเพื่อตรวจสอบและหนึ่งแทรกเป็นชุดผลลัพธ์คือ ว่างเปล่า)?

ที่ไม่uniqueจำกัด ในการรับประกันข้อมูลที่insertจะล้มเหลวถ้ามันมีอยู่แล้ว?

ดูเหมือนว่ามีเพียงข้อ จำกัด เมื่อฉันออกแทรกผ่าน php สคริปต์ croaks



ดูstackoverflow.com/questions/44550788/…สำหรับการสนทนาเกี่ยวกับการไม่เผาค่า auto_inc
Rick James

@RickJames - นั่นเป็นคำถามที่น่าสนใจ .. แต่ไม่แน่ใจว่าเกี่ยวข้องโดยตรงกับคำถามนี้หรือไม่ :)
warren

1
มันถูกกล่าวถึงในความคิดเห็นและคำถามอื่นอ้างว่าคำถามนี้เป็น "ซ้ำกันแน่นอน" ดังนั้นฉันรู้สึกว่ามันเป็นความคิดที่ดีที่จะเชื่อมโยงคำถามเข้าด้วยกันเพื่อประโยชน์ของผู้อื่น
Rick James

1
โอ้ฉันไม่เคยคิดที่จะมองที่แถบด้านข้าง
Rick James

คำตอบ:


806

ใช้ INSERT IGNORE INTO table

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

นอกจากนี้ยังมีINSERT … ON DUPLICATE KEY UPDATEไวยากรณ์คุณสามารถค้นหาคำอธิบายได้ที่dev.mysql.com


โพสต์จาก bogdan.org.ua ตาม webcache ของ Google :

18 ตุลาคม 2550

ในการเริ่มต้น: จาก MySQL ล่าสุดไม่สามารถใช้ไวยากรณ์ที่ปรากฏในชื่อเรื่องได้ แต่มีวิธีง่าย ๆ หลายวิธีในการบรรลุสิ่งที่คาดหวังโดยใช้ฟังก์ชันการทำงานที่มีอยู่

มีวิธีแก้ปัญหา 3 วิธีที่เป็นไปได้: ใช้ INSERT IGNORE, REPLACE หรือ INSERT ... ในการอัปเดต KEY ซ้ำซ้อน

ลองนึกภาพเรามีตาราง:

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;

ทีนี้ลองนึกภาพว่าเรามีเมตาดาต้าไพพ์ไลน์แบบอัตโนมัติที่นำเข้าทรานสคริปต์ข้อมูลจาก Ensembl และด้วยเหตุผลหลายประการไพพ์ไลน์อาจเสียในทุกขั้นตอนของการดำเนินการ ดังนั้นเราต้องมั่นใจว่ามีสองสิ่ง:

  1. การเรียกใช้งานท่อซ้ำหลายครั้งจะไม่ทำลายฐานข้อมูลของเรา

  2. การประมวลผลซ้ำ ๆ จะไม่ตายเนื่องจากข้อผิดพลาด 'คีย์หลักที่ซ้ำกัน'

วิธีที่ 1: ใช้ REPLACE

มันง่ายมาก:

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

หากมีบันทึกอยู่มันจะถูกเขียนทับ หากยังไม่มีอยู่จะถูกสร้างขึ้น อย่างไรก็ตามการใช้วิธีนี้ไม่ได้มีประสิทธิภาพสำหรับกรณีของเรา: เราไม่จำเป็นต้องเขียนทับระเบียนที่มีอยู่มันก็แค่ข้ามไป

วิธีที่ 2: ใช้ INSERT IGNORE ง่ายมากเช่นกัน:

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

ที่นี่หาก 'ensembl_transcript_id' มีอยู่ในฐานข้อมูลแล้วจะถูกข้ามแบบเงียบ ๆ (ละเว้น) (เพื่อความแม่นยำมากขึ้นต่อไปนี้เป็นคำพูดจากคู่มืออ้างอิง MySQL:“ หากคุณใช้คำสำคัญ IGNORE ข้อผิดพลาดที่เกิดขึ้นขณะดำเนินการคำสั่ง INSERT จะถือว่าเป็นการเตือนแทนเช่นไม่มี IGNORE แถวที่ซ้ำดัชนี UNIQUE ที่มีอยู่เดิม หรือค่าคีย์หลักในตารางทำให้เกิดข้อผิดพลาดซ้ำกันของคีย์และคำสั่งจะถูกยกเลิก”) หากยังไม่มีการบันทึกข้อมูลมันจะถูกสร้างขึ้น

วิธีที่สองนี้มีจุดอ่อนหลายประการรวมถึงการไม่ทำแท้งของแบบสอบถามในกรณีที่มีปัญหาอื่น ๆ เกิดขึ้น (ดูคู่มือ) ดังนั้นจึงควรใช้หากทดสอบก่อนหน้านี้โดยไม่มีคำหลัก IGNORE

วิธีที่ 3: ใช้ INSERT ... ในการอัปเดตคีย์ซ้ำกัน:

ตัวเลือกที่สามคือการใช้INSERT … ON DUPLICATE KEY UPDATE ไวยากรณ์และในส่วน UPDATE ไม่ได้ทำอะไรเลยการดำเนินการที่ไม่มีความหมาย (ว่างเปล่า) เช่นการคำนวณ 0 + 0 (Geoffray แนะนำให้ทำการกำหนด id = id สำหรับเครื่องมือเพิ่มประสิทธิภาพ MySQL เพื่อละเว้นการดำเนินการนี้) ข้อดีของวิธีนี้คือการละเว้นเหตุการณ์สำคัญที่ซ้ำกันเท่านั้นและยังคงยกเลิกข้อผิดพลาดอื่น ๆ

เป็นการแจ้งให้ทราบล่วงหน้า: โพสต์นี้ได้รับแรงบันดาลใจจาก Xaprb ฉันยังแนะนำให้ปรึกษาโพสต์อื่น ๆ ของเขาเกี่ยวกับการเขียนแบบสอบถาม SQL ที่ยืดหยุ่น


3
และฉันสามารถรวมกับ "ล่าช้า" เพื่อเพิ่มความเร็วสคริปต์ได้หรือไม่
วอร์เรน

3
ใช่การแทรกล่าช้าอาจช่วยเพิ่มความเร็วให้กับคุณได้ ลองมันออกมา
2552


10
INSERT … ON DUPLICATE KEY UPDATEดีกว่าเนื่องจากจะไม่ลบแถวรักษาauto_incrementคอลัมน์และข้อมูลอื่น ๆ
redolent

15
เพียงเพื่อแจ้งให้ทุกคน การใช้INSERT … ON DUPLICATE KEY UPDATEเมธอดจะเพิ่มคอลัมน์ AUTO_INCREMENT ใด ๆ ด้วยการแทรกที่ล้มเหลว อาจเป็นเพราะมันไม่ได้ล้มเหลวจริงๆ แต่เป็น UPDATE
not2qubit

216

สารละลาย:

INSERT INTO `table` (`value1`, `value2`) 
SELECT 'stuff for value1', 'stuff for value2' FROM DUAL 
WHERE NOT EXISTS (SELECT * FROM `table` 
      WHERE `value1`='stuff for value1' AND `value2`='stuff for value2' LIMIT 1) 

คำอธิบาย:

แบบสอบถามด้านในสุด

SELECT * FROM `table` 
      WHERE `value1`='stuff for value1' AND `value2`='stuff for value2' LIMIT 1

ใช้เป็นWHERE NOT EXISTS-condition ตรวจพบว่ามีแถวที่มีข้อมูลถูกแทรกอยู่แล้ว หลังจากพบแถวหนึ่งของประเภทนี้แล้วแบบสอบถามอาจหยุดทำงานดังนั้นLIMIT 1(การเพิ่มประสิทธิภาพแบบไมโครอาจถูกละไว้)

แบบสอบถามระดับกลาง

SELECT 'stuff for value1', 'stuff for value2' FROM DUAL

แทนค่าที่จะแทรก DUALหมายถึงพิเศษหนึ่งแถวตารางหนึ่งคอลัมน์ที่มีอยู่โดยค่าเริ่มต้นในฐานข้อมูล Oracle ทั้งหมด (ดูhttps://en.wikipedia.org/wiki/DUAL_table ) บน MySQL-Server เวอร์ชัน 5.7.26 ฉันได้รับข้อความค้นหาที่ถูกต้องเมื่อข้ามFROM DUALแต่ดูเหมือนว่ารุ่นเก่ากว่า (เช่น 5.5.60) ต้องการFROMข้อมูล โดยใช้WHERE NOT EXISTSแบบสอบถามกลางส่งกลับชุดผลลัพธ์ที่ว่างเปล่าหากแบบสอบถามด้านในสุดพบข้อมูลที่ตรงกัน

แบบสอบถามภายนอก

INSERT INTO `table` (`value1`, `value2`) 

แทรกข้อมูลหากมีการส่งคืนโดยแบบสอบถามระดับกลาง


4
คุณสามารถให้ข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้สิ่งนี้ได้ไหม?
Alex V

36
ตัวแปรนี้เหมาะถ้าไม่มีคีย์ที่ไม่ซ้ำกันบนโต๊ะที่มีอยู่ ( INSERT IGNOREและINSERT ON DUPLICATE KEYจำเป็นต้องมีข้อ จำกัด ที่สำคัญไม่ซ้ำกัน)
rabudde

2
หากคุณใช้ "จากคู่" ในบรรทัด 2 แทน "จากตาราง" คุณไม่จำเป็นต้องมีประโยค "จำกัด 1"
รวย

6
เกิดอะไรขึ้นถ้าstuff for value1และstuff for value2เหมือนกัน? นี่จะเป็นการโยนDuplicate column name
Robin

1
ฉันชอบSELECT 1มากกว่าSELECT *ในแบบสอบถามย่อยด้วย มีโอกาสมากขึ้นที่สิ่งนี้จะได้รับความพึงพอใจจากดัชนี
Arth

58

ในการอัปเดตคีย์ซ้ำหรือการเพิกเฉยการแทรกสามารถเป็นโซลูชันที่ทำงานได้กับ MySQL


ตัวอย่างการอัปเดตการอัปเดตคีย์ที่ซ้ำกันตาม mysql.com

INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE c=c+1;

UPDATE table SET c=c+1 WHERE a=1;

ตัวอย่างของการเพิกเฉยการแทรกตาม mysql.com

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]

หรือ:

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    SET col_name={expr | DEFAULT}, ...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]

หรือ:

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]

24

ข้อ จำกัด ง่ายๆใด ๆ ที่ควรทำงานถ้าข้อยกเว้นเป็นที่ยอมรับ ตัวอย่าง :

  • คีย์หลักหากไม่ได้เป็นตัวแทน
  • ข้อ จำกัด ที่ไม่ซ้ำกันในคอลัมน์
  • ข้อ จำกัด เฉพาะหลายคอลัมน์

ขออภัยนี่ดูเหมือนง่าย ๆ ที่หลอกลวง ฉันรู้ว่าหน้าตาของลิงก์ที่คุณแชร์กับเรานั้นแย่มาก ;-(

แต่ฉันไม่เคยให้คำตอบนี้เพราะมันดูเหมือนจะเติมเต็มความต้องการของคุณ (หากไม่เป็นเช่นนั้นอาจทำให้เกิดการอัพเดทข้อกำหนดของคุณซึ่งก็จะเป็น "สิ่งที่ดี" (TM) ด้วย)

แก้ไข : หากส่วนแทรกจะทำลายข้อ จำกัด ที่ไม่ซ้ำกันของฐานข้อมูลข้อยกเว้นจะถูกส่งไปที่ระดับฐานข้อมูลซึ่งถ่ายทอดโดยไดรเวอร์ มันจะหยุดสคริปต์ของคุณอย่างแน่นอนด้วยความล้มเหลว มันจะต้องเป็นไปได้ใน PHP เพื่อที่กรณีนี้ ...


1
ฉันได้เพิ่มความกระจ่างให้กับคำถาม - คำตอบของคุณยังใช้อยู่หรือไม่?
วอร์เรน

2
ฉันเชื่อว่ามันเป็นเช่นนั้น ข้อ จำกัด ที่ไม่ซ้ำกันจะทำให้เกิดความล้มเหลวของการแทรกไม่ถูกต้อง หมายเหตุ: คุณต้องจัดการกับความล้มเหลวนี้ในรหัสของคุณ แต่มันค่อนข้างมาตรฐาน
KLE

1
สำหรับตอนนี้ผมกำลังจะไปติดกับการแก้ปัญหาที่ผมได้รับการยอมรับ - แต่ต่อไปจะมีลักษณะเป็นความล้มเหลวของการจัดการ INSERT ฯลฯ เป็น app ที่เติบโตขึ้น
วอร์เรน

3
INSERT IGNOREเปลี่ยนข้อผิดพลาดทั้งหมดเป็นคำเตือนโดยทั่วไปเพื่อให้สคริปต์ของคุณไม่ถูกขัดจังหวะ จากนั้นคุณสามารถดูคำเตือนใด ๆ SHOW WARNINGSกับคำสั่ง และหมายเหตุสำคัญอื่น ๆ: ข้อ จำกัด ที่ไม่ซ้ำกันจะไม่ทำงานกับค่า NULL เช่น row1 (1, NULL) และ row2 (1, NULL) จะถูกแทรกทั้งคู่ (เว้นแต่มีข้อ จำกัด อื่นเช่นคีย์หลักเสีย) โชคร้าย
Simon East

18

นี่คือฟังก์ชัน PHP ที่จะแทรกแถวเฉพาะในกรณีที่ค่าคอลัมน์ที่ระบุทั้งหมดไม่มีอยู่ในตาราง

  • หากหนึ่งในคอลัมน์แตกต่างกันแถวจะถูกเพิ่ม

  • หากตารางนั้นว่างแถวจะถูกเพิ่ม

  • หากมีแถวที่คอลัมน์ทั้งหมดที่ระบุมีค่าที่ระบุแถวจะไม่ถูกเพิ่ม

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

ตัวอย่างการใช้งาน:

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

5
ค่อนข้างแพงถ้าคุณมีการแทรกจำนวนมาก
ЭџadДьdulяңмaи

จริง แต่มีประสิทธิภาพหากคุณจำเป็นต้องเพิ่มการตรวจร่างกายโดยเฉพาะ
Charles Forest

1
คำเตือน: mysql_*ส่วนขยายถูกเลิกใช้ตั้งแต่ PHP 5.5.0 และถูกลบออกตั้งแต่ PHP 7.0.0 แต่ทั้งmysqliหรือPDO_MySQLนามสกุลควรใช้ ดูภาพรวม MySQL APIสำหรับความช่วยเหลือเพิ่มเติมในขณะที่เลือก MySQL API
Dharman

17
REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;

หากมีบันทึกอยู่มันจะถูกเขียนทับ หากยังไม่มีอยู่จะถูกสร้างขึ้น


10
REPLACEอาจลบแถวแล้วแทรกแทนการอัปเดต ผลข้างเคียงคือข้อ จำกัด อาจลบวัตถุอื่นและลบทริกเกอร์
xmedeko

1
จากคู่มือ MySQL: "REPLACE เหมาะสมต่อเมื่อตารางมีดัชนีหลักหรือ UNIQUE ดัชนีมิฉะนั้นมันจะเทียบเท่ากับ INSERT เพราะไม่มีดัชนีที่จะใช้เพื่อกำหนดว่าแถวใหม่จะทำซ้ำแถวอื่นหรือไม่"
BurninLeo

16

ลองทำสิ่งต่อไปนี้:

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

5
ลองคำตอบนี้มีค่าต่ำใน StackOverflow เพราะทำน้อยมากเพื่อให้ความรู้แก่ OP และนักวิจัยหลายพันคนในอนาคต โปรดแก้ไขคำตอบนี้เพื่อรวมวิธีแก้ปัญหาและทำไมจึงเป็นความคิดที่ดี
mickmackusa

1
โซลูชั่นที่สมบูรณ์แบบในกรณีที่เขตข้อมูลที่จะจับคู่ไม่ใช่กุญแจ .. !
Leo

6

มีหลายคำตอบที่ครอบคลุมถึงวิธีการแก้ปัญหานี้ถ้าคุณมีเป็นUNIQUEดัชนีที่คุณสามารถตรวจสอบกับกับหรือON DUPLICATE KEY INSERT IGNOREกรณีนี้อาจไม่เสมอไปและเนื่องจากUNIQUEมีข้อจำกัดความยาว (1,000 ไบต์) คุณอาจไม่สามารถเปลี่ยนแปลงได้ ตัวอย่างเช่นฉันต้องทำงานกับเมตาดาต้าใน WordPress (wp_postmeta )

ในที่สุดฉันก็แก้มันได้ด้วยแบบสอบถามสองข้อ:

UPDATE wp_postmeta SET meta_value = ? WHERE meta_key = ? AND post_id = ?;
INSERT INTO wp_postmeta (post_id, meta_key, meta_value) SELECT DISTINCT ?, ?, ? FROM wp_postmeta WHERE NOT EXISTS(SELECT * FROM wp_postmeta WHERE meta_key = ? AND post_id = ?);

Query 1 เป็นUPDATEแบบสอบถามทั่วไปที่ไม่มีผลกระทบเมื่อไม่มีชุดข้อมูลที่เป็นปัญหา Query 2 เป็นสิ่งINSERTที่ขึ้นอยู่กับ a NOT EXISTSคือINSERTจะดำเนินการเฉพาะเมื่อไม่มีชุดข้อมูล


2

สิ่งที่ควรสังเกตคือ INSERT IGNORE จะยังคงเพิ่มคีย์หลักไม่ว่าคำสั่งนั้นจะประสบความสำเร็จหรือไม่เหมือนกับ INSERT ทั่วไป

สิ่งนี้จะทำให้เกิดช่องว่างในคีย์หลักของคุณซึ่งอาจทำให้โปรแกรมเมอร์ไม่เสถียรทางจิตใจ หรือหากแอปพลิเคชันของคุณได้รับการออกแบบไม่ดีและขึ้นอยู่กับปุ่มหลักที่เพิ่มขึ้นอย่างสมบูรณ์แบบมันอาจกลายเป็นอาการปวดหัว

ดูinnodb_autoinc_lock_mode = 0(การตั้งค่าเซิร์ฟเวอร์และมาพร้อมกับประสิทธิภาพเล็กน้อย) หรือใช้ SELECT ก่อนเพื่อให้แน่ใจว่าแบบสอบถามของคุณจะไม่ล้มเหลว (ซึ่งมาพร้อมกับประสิทธิภาพและรหัสพิเศษ)


ทำไม "ช่องว่างในคีย์หลักของคุณ" - ถึงแม้จะเป็น - "ทำให้โปรแกรมเมอร์ไม่มั่นคงทางจิตใจ"? ช่องว่างเกิดขึ้นตลอดเวลาในคีย์หลัก - ทุกครั้งที่คุณลบระเบียนเช่น
warren

เริ่มต้นด้วยความSELECTพ่ายแพ้จุดประสงค์ทั้งหมดเพียงแค่ส่งชุดใหญ่ออกไปINSERTและไม่ต้องการกังวลเกี่ยวกับการซ้ำซ้อน
warren

2

อัปเดตหรือแทรกโดยไม่ทราบคีย์หลัก

หากคุณมีคีย์เฉพาะหรือคีย์หลักอยู่แล้วคำตอบอื่น ๆ ที่มีINSERT INTO ... ON DUPLICATE KEY UPDATE ...หรือREPLACE INTO ...ควรจะทำงานได้ดี (โปรดทราบว่าแทนที่เป็นลบหากมีอยู่แล้วแทรก - จึงไม่ปรับปรุงค่าที่มีอยู่บางส่วน)

แต่ถ้าคุณมีค่าสำหรับsome_column_idและsome_typeการรวมกันของที่เป็นเอกลักษณ์ และคุณต้องการอัปเดตsome_valueหากมีอยู่หรือแทรกหากไม่มีอยู่ และคุณต้องการทำในแบบสอบถามเดียว (เพื่อหลีกเลี่ยงการใช้ธุรกรรม) นี่อาจเป็นทางออก:

INSERT INTO my_table (id, some_column_id, some_type, some_value)
SELECT t.id, t.some_column_id, t.some_type, t.some_value
FROM (
    SELECT id, some_column_id, some_type, some_value
    FROM my_table
    WHERE some_column_id = ? AND some_type = ?
    UNION ALL
    SELECT s.id, s.some_column_id, s.some_type, s.some_value
    FROM (SELECT NULL AS id, ? AS some_column_id, ? AS some_type, ? AS some_value) AS s
) AS t
LIMIT 1
ON DUPLICATE KEY UPDATE
some_value = ?

โดยทั่วไปแบบสอบถามจะดำเนินการด้วยวิธีนี้ (ซับซ้อนน้อยกว่าที่อาจมีลักษณะ):

  • เลือกแถวที่มีอยู่ผ่านการWHEREจับคู่ประโยค
  • รวมที่ผลลัพธ์ด้วยแถวใหม่ที่เป็นไปได้ (ตารางs) ซึ่งค่าคอลัมน์จะได้รับอย่างชัดเจน (s.id คือ NULL ดังนั้นมันจะสร้างตัวระบุการเพิ่มขึ้นอัตโนมัติใหม่)
  • ถ้าแถวที่มีอยู่พบแล้วแถวใหม่ที่มีศักยภาพจากตารางsจะถูกยกเลิก (เนื่องจาก LIMIT 1 บนโต๊ะt) และมันมักจะเรียกON DUPLICATE KEYซึ่งจะคอลัมน์UPDATEsome_value
  • หากไม่พบแถวที่มีอยู่จะมีการแทรกแถวใหม่ที่อาจเกิดขึ้น (ตามที่กำหนดโดยตารางs)

หมายเหตุ: ทุกตารางในฐานข้อมูลเชิงสัมพันธ์ควรมีอย่างน้อยidคอลัมน์การเพิ่มอัตโนมัติหลัก หากคุณไม่มีสิ่งนี้ให้เพิ่มเข้าไปแม้ในตอนแรกที่คุณไม่ต้องการมัน จำเป็นอย่างยิ่งสำหรับ "เคล็ดลับ" นี้


ผู้ตอบคำถามอีกหลายคนแสดงINSERT INTO ... SELECT FROMรูปแบบแล้ว ทำไมคุณถึงยัง
วอร์เรน

2
@warren ไม่ว่าคุณจะไม่ได้อ่านคำตอบของฉันคุณไม่เข้าใจหรือฉันไม่ได้อธิบายอย่างถูกต้อง ไม่ว่าในกรณีใดผมขอเน้นสิ่งต่อไปนี้: นี่ไม่ใช่แค่INSERT INTO... SELECT FROM...วิธีแก้ปัญหาปกติ โปรดอ้างอิงถึงลิงค์ไปยังคำตอบที่เหมือนกันหากคุณสามารถหาได้ฉันจะลบคำตอบนี้มิฉะนั้นคุณจะตอบคำตอบของฉัน (ข้อตกลง?) ตรวจสอบให้แน่ใจว่าคำตอบที่คุณจะเชื่อมโยงใช้เพียง 1 แบบสอบถาม (สำหรับการอัปเดต + การแทรก) ไม่มีการทำธุรกรรมและสามารถกำหนดเป้าหมายการรวมกันของคอลัมน์ใด ๆ ที่เป็นที่รู้จักว่าไม่ซ้ำกัน ต้องไม่ซ้ำกัน)
Yeti
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.