2016-12-23 8 views
6

मुझे कोई समस्या नहीं है MySQL 5.6 InnoDb INSERT INTO xxx (col) SELECT ... चलाते समय एक गैर-विदेशी विदेशी कुंजी को अनदेखा कर रहा है। अन्य प्रारूपों में सम्मिलन बयान चलाते समय बाधा ठीक से लागू होती है। विदेशी कुंजी चेकों सक्षम हैं, और sql_mode = STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ENGINE_SUBSTITUTIONMySQL सम्मिलित करें चयन न करें पूर्ण अवरोध

यहाँ एक उदाहरण है:

CREATE TABLE Test_Parent 
(
    id BIGINT(18) UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT, 
    dummy VARCHAR(255) 
) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci 
    COMMENT 'Test parent table'; 

CREATE TABLE Test_Child 
(
    id BIGINT(18) unsigned PRIMARY KEY NOT NULL AUTO_INCREMENT, 
    fid BIGINT UNSIGNED NOT NULL, 
    FOREIGN KEY Fk_Test_Parent_01(fid) REFERENCES Test_Parent(id) 
) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci 
    COMMENT 'Test child table'; 

INSERT INTO Test_Parent(dummy) 
VALUES ('test'); 

## Here's where the FK constraint should be enforced but isn't ## 
INSERT INTO Test_Child(fid) 
SELECT id 
    FROM Test_Parent 
WHERE dummy = 'missing value'; 

1 row affected in 5ms 

## Running an insert with a different format, the constraint is enforced ## 
INSERT INTO Test_Child(fid) 
VALUES (null); 
Column 'fid' cannot be null 

## Running this format, the foreign key is also enforced ## 
INSERT INTO Test_Child(id, fid) 
VALUES (123, (SELECT id FROM Test_Parent WHERE dummy = 'missing value')); 
Column 'fid' cannot be null 

मुझे समझ नहीं आता क्यों MySQL 3 डालने बयानों में से 2 के लिए विदेशी कुंजी को लागू करेगा। कोई विचार?

+1

मुझे आश्चर्य है कि अगर आप एक गलत "1 पंक्ति प्रभावित" देख रहे हैं क्योंकि कि 'INSERT ... SELECT' वास्तव में किसी भी पंक्ति सम्मिलित नहीं होता है क्योंकि 'WHERE' क्लॉज मेल नहीं खाता है। यदि मैं दोनों टेबलों से 'चयन * करता हूं, तो मुझे 'Test_Child' में कोई पंक्ति नहीं दिखाई देती है ... http: //sqlfiddle.com/#! 9/7413e0/1 –

+0

यह तब तक है जब तक कि आपका वास्तविक डेटा और उपयोग केस महत्वपूर्ण रूप से भिन्न न हो टेस्ट सेट जो आपने हमारे लिए सेट किया है। –

+0

यह सही है - यह 1 पंक्ति को डालने के रूप में रिपोर्ट करता है, लेकिन वास्तव में तालिका में कुछ भी डाला नहीं गया है। मैं उम्मीद करता हूं कि इस परिदृश्य में 'न्यूल' की बाधा लागू नहीं होगी। इसके बजाए, ऐसा लगता है कि अपवाद निगल गया है। – adam

उत्तर

1

आपके ग्राहक से एक भ्रामक 1 row affected in 5ms संदेश यहां भ्रम का स्रोत हो सकता है। टिप्पणी थ्रेड में आपने बताया कि IntelliJ उस संदेश की रिपोर्ट कर रहा था, लेकिन मैंने MySQL 5.6.35 और 5.7.16-ubuntu दोनों में आपकी अच्छी तरह से परिभाषित परीक्षण तालिकाओं को चलाया और दोनों संस्करणों में प्रश्न में बयान 0 प्रभावित पंक्तियों की सूचना दी:

mysql > INSERT INTO Test_Child(fid) 
    -> SELECT id 
    ->  FROM Test_Parent 
    -> WHERE dummy = 'missing value'; 
Query OK, 0 rows affected (0.00 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

तो भ्रामक प्रभावित पंक्तियों के संदेश को देखते हुए, वास्तव में यहां क्या हो रहा है यह है कि SELECT आपके INSERT...SELECT कथन का कोई पंक्ति नहीं है, और इसलिए MySQL किसी भी पंक्ति को सम्मिलित करने का प्रयास नहीं करता है। इसलिए कोई विदेशी कुंजी बाधा उल्लंघन नहीं था।

INSERT INTO...SELECT का प्रारूप आपके बाद में उदाहरण से थोड़ी अलग है:

INSERT INTO Test_Child(id, fid) 
VALUES (123, (SELECT id FROM Test_Parent WHERE dummy = 'missing value')); 

... क्योंकि इस मामले में, आंकिक शाब्दिक 123 बलों एक पंक्ति सम्मिलित करने के लिए, और यह एक null साथ जोड़ा जाता है उप-चयन से मूल्य वापस आ गया। ताकि null को बाधा उल्लंघन का कारण बनने और उसका कारण बनने का प्रयास किया जा सके।

आप INSERT...SELECT एक शून्य मान के साथ एक पंक्ति लौटने के लिए मजबूर हैं, तो आप असफल कर सकते हैं एक बाधा उल्लंघन के कारण:

INSERT INTO Test_Child (fid) 
-- Return a literal NULL row... 
SELECT NULL as id FROM Test_Parent 
-- Column fid cannot be null 
संबंधित मुद्दे