2010-02-12 21 views
52

मेरे पास InnoDB टेबल का एक सेट है जिसे मुझे समय-समय पर कुछ पंक्तियों को हटाने और दूसरों को डालने से बनाए रखने की आवश्यकता होती है। कई तालिकाओं में अन्य तालिकाओं का संदर्भ देने वाली विदेशी कुंजी बाधाएं हैं, इसलिए इसका मतलब है कि तालिका लोडिंग ऑर्डर महत्वपूर्ण है। तालिकाओं के आदेश के बारे में चिंता किए बिना नई पंक्तियाँ सम्मिलित करने के लिए, मैं का उपयोग करें:फोर्स इनो डीबी एक टेबल/टेबल पर विदेशी कुंजी को फिर से जांचने के लिए?

SET FOREIGN_KEY_CHECKS=0; 
से पहले

, और उसके बाद:

SET FOREIGN_KEY_CHECKS=1; 

के बाद।

जब लोडिंग पूर्ण हो जाती है, तो मैं यह जांचना चाहता हूं कि अद्यतन तालिकाओं में डेटा अभी भी रेफरेंसियल अखंडता धारण करता है - कि नई पंक्तियां विदेशी कुंजी बाधाओं को तोड़ती नहीं हैं - लेकिन ऐसा लगता है कि इसका कोई तरीका नहीं है यह करो।

एक परीक्षण के रूप में, मैंने डेटा दर्ज किया कि मुझे यकीन है कि विदेशी कुंजी बाधाओं का उल्लंघन किया गया है, और विदेशी कुंजी जांच को फिर से सक्षम करने पर, MySQL ने कोई चेतावनी या त्रुटियां नहीं बनाई हैं।

यदि मैंने टेबल लोडिंग ऑर्डर निर्दिष्ट करने का कोई तरीका ढूंढने का प्रयास किया है, और लोडिंग प्रक्रिया के दौरान विदेशी कुंजी चेक छोड़ दिया है, तो यह मुझे उस तालिका में डेटा लोड करने की अनुमति नहीं देगा जिसमें एक आत्म-संदर्भित विदेशी कुंजी बाधा है , तो यह एक स्वीकार्य समाधान नहीं होगा।

क्या किसी तालिका या डेटाबेस की विदेशी कुंजी बाधाओं को सत्यापित करने के लिए InnoDB को मजबूर करने का कोई तरीका है?

उत्तर

87
DELIMITER $$ 

DROP PROCEDURE IF EXISTS ANALYZE_INVALID_FOREIGN_KEYS$$ 

CREATE 
    PROCEDURE `ANALYZE_INVALID_FOREIGN_KEYS`(
     checked_database_name VARCHAR(64), 
     checked_table_name VARCHAR(64), 
     temporary_result_table ENUM('Y', 'N')) 

    LANGUAGE SQL 
    NOT DETERMINISTIC 
    READS SQL DATA 

    BEGIN 
     DECLARE TABLE_SCHEMA_VAR VARCHAR(64); 
     DECLARE TABLE_NAME_VAR VARCHAR(64); 
     DECLARE COLUMN_NAME_VAR VARCHAR(64); 
     DECLARE CONSTRAINT_NAME_VAR VARCHAR(64); 
     DECLARE REFERENCED_TABLE_SCHEMA_VAR VARCHAR(64); 
     DECLARE REFERENCED_TABLE_NAME_VAR VARCHAR(64); 
     DECLARE REFERENCED_COLUMN_NAME_VAR VARCHAR(64); 
     DECLARE KEYS_SQL_VAR VARCHAR(1024); 

     DECLARE done INT DEFAULT 0; 

     DECLARE foreign_key_cursor CURSOR FOR 
      SELECT 
       `TABLE_SCHEMA`, 
       `TABLE_NAME`, 
       `COLUMN_NAME`, 
       `CONSTRAINT_NAME`, 
       `REFERENCED_TABLE_SCHEMA`, 
       `REFERENCED_TABLE_NAME`, 
       `REFERENCED_COLUMN_NAME` 
      FROM 
       information_schema.KEY_COLUMN_USAGE 
      WHERE 
       `CONSTRAINT_SCHEMA` LIKE checked_database_name AND 
       `TABLE_NAME` LIKE checked_table_name AND 
       `REFERENCED_TABLE_SCHEMA` IS NOT NULL; 

     DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 

     IF temporary_result_table = 'N' THEN 
      DROP TEMPORARY TABLE IF EXISTS INVALID_FOREIGN_KEYS; 
      DROP TABLE IF EXISTS INVALID_FOREIGN_KEYS; 

      CREATE TABLE INVALID_FOREIGN_KEYS(
       `TABLE_SCHEMA` VARCHAR(64), 
       `TABLE_NAME` VARCHAR(64), 
       `COLUMN_NAME` VARCHAR(64), 
       `CONSTRAINT_NAME` VARCHAR(64), 
       `REFERENCED_TABLE_SCHEMA` VARCHAR(64), 
       `REFERENCED_TABLE_NAME` VARCHAR(64), 
       `REFERENCED_COLUMN_NAME` VARCHAR(64), 
       `INVALID_KEY_COUNT` INT, 
       `INVALID_KEY_SQL` VARCHAR(1024) 
      ); 
     ELSEIF temporary_result_table = 'Y' THEN 
      DROP TEMPORARY TABLE IF EXISTS INVALID_FOREIGN_KEYS; 
      DROP TABLE IF EXISTS INVALID_FOREIGN_KEYS; 

      CREATE TEMPORARY TABLE INVALID_FOREIGN_KEYS(
       `TABLE_SCHEMA` VARCHAR(64), 
       `TABLE_NAME` VARCHAR(64), 
       `COLUMN_NAME` VARCHAR(64), 
       `CONSTRAINT_NAME` VARCHAR(64), 
       `REFERENCED_TABLE_SCHEMA` VARCHAR(64), 
       `REFERENCED_TABLE_NAME` VARCHAR(64), 
       `REFERENCED_COLUMN_NAME` VARCHAR(64), 
       `INVALID_KEY_COUNT` INT, 
       `INVALID_KEY_SQL` VARCHAR(1024) 
      ); 
     END IF; 


     OPEN foreign_key_cursor; 
     foreign_key_cursor_loop: LOOP 
      FETCH foreign_key_cursor INTO 
      TABLE_SCHEMA_VAR, 
      TABLE_NAME_VAR, 
      COLUMN_NAME_VAR, 
      CONSTRAINT_NAME_VAR, 
      REFERENCED_TABLE_SCHEMA_VAR, 
      REFERENCED_TABLE_NAME_VAR, 
      REFERENCED_COLUMN_NAME_VAR; 
      IF done THEN 
       LEAVE foreign_key_cursor_loop; 
      END IF; 


      SET @from_part = CONCAT('FROM ', '`', TABLE_SCHEMA_VAR, '`.`', TABLE_NAME_VAR, '`', ' AS REFERRING ', 
       'LEFT JOIN `', REFERENCED_TABLE_SCHEMA_VAR, '`.`', REFERENCED_TABLE_NAME_VAR, '`', ' AS REFERRED ', 
       'ON (REFERRING', '.`', COLUMN_NAME_VAR, '`', ' = ', 'REFERRED', '.`', REFERENCED_COLUMN_NAME_VAR, '`', ') ', 
       'WHERE REFERRING', '.`', COLUMN_NAME_VAR, '`', ' IS NOT NULL ', 
       'AND REFERRED', '.`', REFERENCED_COLUMN_NAME_VAR, '`', ' IS NULL'); 
      SET @full_query = CONCAT('SELECT COUNT(*) ', @from_part, ' INTO @invalid_key_count;'); 
      PREPARE stmt FROM @full_query; 

      EXECUTE stmt; 
      IF @invalid_key_count > 0 THEN 
       INSERT INTO 
        INVALID_FOREIGN_KEYS 
       SET 
        `TABLE_SCHEMA` = TABLE_SCHEMA_VAR, 
        `TABLE_NAME` = TABLE_NAME_VAR, 
        `COLUMN_NAME` = COLUMN_NAME_VAR, 
        `CONSTRAINT_NAME` = CONSTRAINT_NAME_VAR, 
        `REFERENCED_TABLE_SCHEMA` = REFERENCED_TABLE_SCHEMA_VAR, 
        `REFERENCED_TABLE_NAME` = REFERENCED_TABLE_NAME_VAR, 
        `REFERENCED_COLUMN_NAME` = REFERENCED_COLUMN_NAME_VAR, 
        `INVALID_KEY_COUNT` = @invalid_key_count, 
        `INVALID_KEY_SQL` = CONCAT('SELECT ', 
         'REFERRING.', '`', COLUMN_NAME_VAR, '` ', 'AS "Invalid: ', COLUMN_NAME_VAR, '", ', 
         'REFERRING.* ', 
         @from_part, ';'); 
      END IF; 
      DEALLOCATE PREPARE stmt; 

     END LOOP foreign_key_cursor_loop; 
    END$$ 

DELIMITER ; 

CALL ANALYZE_INVALID_FOREIGN_KEYS('%', '%', 'Y'); 
DROP PROCEDURE IF EXISTS ANALYZE_INVALID_FOREIGN_KEYS; 

SELECT * FROM INVALID_FOREIGN_KEYS; 

आप अवैध संग्रहीत कुंजी के लिए सभी डेटाबेस को जांचने के लिए इस संग्रहीत प्रक्रिया का उपयोग कर सकते हैं। परिणाम INVALID_FOREIGN_KEYS तालिका में लोड किया जाएगा। ANALYZE_INVALID_FOREIGN_KEYS की पैरामीटर:

  1. डेटाबेस नाम पैटर्न (शैली की तरह)
  2. तालिका नाम पैटर्न (शैली की तरह)
  3. परिणाम अस्थायी हो जाएगा या नहीं। यह हो सकता है: 'Y', 'N', NULL

    • 'Y' के मामले में ANALYZE_INVALID_FOREIGN_KEYS परिणाम तालिका अस्थायी तालिका हो जाएगा। अस्थायी तालिका अन्य सत्रों के लिए दृश्यमान नहीं होगी। आप अस्थायी परिणाम तालिका के साथ समांतर रूप से संग्रहीत प्रक्रिया ANALYZE_INVALID_FOREIGN_KEYS(...) निष्पादित कर सकते हैं।
    • लेकिन यदि आप किसी अन्य सत्र से आंशिक परिणाम में रूचि रखते हैं, तो आपको 'N' का उपयोग करना होगा, फिर किसी अन्य सत्र से SELECT * FROM INVALID_FOREIGN_KEYS; निष्पादित करना होगा।
    • आप लेन-देन में परिणाम तालिका निर्माण छोड़ना, क्योंकि MySQL कार्यान्वित निहित CREATE TABLE ... और DROP TABLE ... के लिए लेन-देन में प्रतिबद्ध है, तो परिणाम तालिका के निर्माण लेनदेन में समस्या का कारण होगा NULL उपयोग करना चाहिए।इस मामले में आप परिणाम तालिका अपने आप को बनाने चाहिए BEGIN; COMMIT/ROLLBACK; ब्लॉक से बाहर:

      CREATE TABLE INVALID_FOREIGN_KEYS(
          `TABLE_SCHEMA` VARCHAR(64), 
          `TABLE_NAME` VARCHAR(64), 
          `COLUMN_NAME` VARCHAR(64), 
          `CONSTRAINT_NAME` VARCHAR(64), 
          `REFERENCED_TABLE_SCHEMA` VARCHAR(64), 
          `REFERENCED_TABLE_NAME` VARCHAR(64), 
          `REFERENCED_COLUMN_NAME` VARCHAR(64), 
          `INVALID_KEY_COUNT` INT, 
          `INVALID_KEY_SQL` VARCHAR(1024) 
      ); 
      

      जाएँ MySQL साइट के बारे में निहित प्रतिबद्ध: http://dev.mysql.com/doc/refman/5.6/en/implicit-commit.html

INVALID_FOREIGN_KEYS पंक्तियों अमान्य का केवल नाम में शामिल होंगे डेटाबेस, टेबल, कॉलम। लेकिन यदि कोई है तो INVALID_FOREIGN_KEYS के INVALID_KEY_SQL कॉलम के निष्पादन के साथ अमान्य रेफरिंग पंक्तियां देख सकते हैं।

रेफरिंग कॉलम (उर्फ विदेशी सूचकांक) और निर्दिष्ट कॉलम (आमतौर पर प्राथमिक कुंजी) पर इंडेक्स होने पर यह संग्रहित प्रक्रिया बहुत तेज होगी।

+0

ग्रेट उत्तर। स्टैक ओवरफ़्लो में आपका स्वागत है! –

+3

मैंने पाया कि मुझे कर्सर में चेक_ * पैरामीटर के बाद 'कोलेट utf8_general_ci' जोड़ना था, क्योंकि मेरी सूचना स्कीमा utf8_general_ci का उपयोग करती है जहां लॉगिन खाता अधिक सही utf8_unicode_ci का उपयोग करता है। इसके बिना मुझे इस तरह के खंड पर एक संयोजन विसंगति त्रुटि मिली। "जहां CONSTRAINT_SCHEMA 'चेक किया गया है चेक_डेटाबेस_नाम collate utf8_general_ci और' TABLE_NAME' चेक_table_name कोलेट utf8_general_ci और 'REFERENCED_TABLE_SCHEMA' शून्य नहीं है; – ClearCrescendo

1

कोई उपकरण नहीं है, जो ऐसा कर सकता है। लेकिन आप एक स्क्रिप्ट लिख सकते हैं, जो आपकी सभी टेबलों के माध्यम से चलेगा, ड्रॉप और विदेशी कुंजी बाधाओं को फिर से बनाएगा। मनोरंजन पर, कुछ गड़बड़ होने पर एक त्रुटि होगी।

15

इस महान उत्तर के लिए धन्यवाद - यह एक बहुत ही आसान टूल है। यहां प्रक्रिया का एक छोटा संशोधित संस्करण है जिसमें आउटपुट टेबल में एसक्यूएल को अमान्य कुंजी के साथ कुंजियों को हटाने के लिए शामिल है - उन मामलों के लिए आसान जहां आपने पुष्टि की है कि ये पंक्तियां गायब/अक्षम हटाए गए कैस्केड नियमों से अनाथ हैं (और प्राथमिक से अनाथ नहीं महत्वपूर्ण परिवर्तन या अन्य जटिल मामलों)।

DELIMITER $$ 

DROP PROCEDURE IF EXISTS ANALYZE_INVALID_FOREIGN_KEYS$$ 

CREATE 
    PROCEDURE `ANALYZE_INVALID_FOREIGN_KEYS`(
     checked_database_name VARCHAR(64), 
     checked_table_name VARCHAR(64), 
     temporary_result_table ENUM('Y', 'N')) 

    LANGUAGE SQL 
    NOT DETERMINISTIC 
    READS SQL DATA 

    BEGIN 
     DECLARE TABLE_SCHEMA_VAR VARCHAR(64); 
     DECLARE TABLE_NAME_VAR VARCHAR(64); 
     DECLARE COLUMN_NAME_VAR VARCHAR(64); 
     DECLARE CONSTRAINT_NAME_VAR VARCHAR(64); 
     DECLARE REFERENCED_TABLE_SCHEMA_VAR VARCHAR(64); 
     DECLARE REFERENCED_TABLE_NAME_VAR VARCHAR(64); 
     DECLARE REFERENCED_COLUMN_NAME_VAR VARCHAR(64); 
     DECLARE KEYS_SQL_VAR VARCHAR(1024); 

     DECLARE done INT DEFAULT 0; 

     DECLARE foreign_key_cursor CURSOR FOR 
      SELECT 
       `TABLE_SCHEMA`, 
       `TABLE_NAME`, 
       `COLUMN_NAME`, 
       `CONSTRAINT_NAME`, 
       `REFERENCED_TABLE_SCHEMA`, 
       `REFERENCED_TABLE_NAME`, 
       `REFERENCED_COLUMN_NAME` 
      FROM 
       information_schema.KEY_COLUMN_USAGE 
      WHERE 
       `CONSTRAINT_SCHEMA` LIKE checked_database_name AND 
       `TABLE_NAME` LIKE checked_table_name AND 
       `REFERENCED_TABLE_SCHEMA` IS NOT NULL; 

     DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 

     IF temporary_result_table = 'N' THEN 
      DROP TEMPORARY TABLE IF EXISTS INVALID_FOREIGN_KEYS; 
      DROP TABLE IF EXISTS INVALID_FOREIGN_KEYS; 

      CREATE TABLE INVALID_FOREIGN_KEYS(
       `TABLE_SCHEMA` VARCHAR(64), 
       `TABLE_NAME` VARCHAR(64), 
       `COLUMN_NAME` VARCHAR(64), 
       `CONSTRAINT_NAME` VARCHAR(64), 
       `REFERENCED_TABLE_SCHEMA` VARCHAR(64), 
       `REFERENCED_TABLE_NAME` VARCHAR(64), 
       `REFERENCED_COLUMN_NAME` VARCHAR(64), 
       `INVALID_KEY_COUNT` INT, 
       `INVALID_KEY_SQL` VARCHAR(1024), 
       `INVALID_KEY_DELETE_SQL` VARCHAR(1024) 
      ); 
     ELSEIF temporary_result_table = 'Y' THEN 
      DROP TEMPORARY TABLE IF EXISTS INVALID_FOREIGN_KEYS; 
      DROP TABLE IF EXISTS INVALID_FOREIGN_KEYS; 

      CREATE TEMPORARY TABLE INVALID_FOREIGN_KEYS(
       `TABLE_SCHEMA` VARCHAR(64), 
       `TABLE_NAME` VARCHAR(64), 
       `COLUMN_NAME` VARCHAR(64), 
       `CONSTRAINT_NAME` VARCHAR(64), 
       `REFERENCED_TABLE_SCHEMA` VARCHAR(64), 
       `REFERENCED_TABLE_NAME` VARCHAR(64), 
       `REFERENCED_COLUMN_NAME` VARCHAR(64), 
       `INVALID_KEY_COUNT` INT, 
       `INVALID_KEY_SQL` VARCHAR(1024), 
       `INVALID_KEY_DELETE_SQL` VARCHAR(1024) 
      ); 
     END IF; 


     OPEN foreign_key_cursor; 
     foreign_key_cursor_loop: LOOP 
      FETCH foreign_key_cursor INTO 
      TABLE_SCHEMA_VAR, 
      TABLE_NAME_VAR, 
      COLUMN_NAME_VAR, 
      CONSTRAINT_NAME_VAR, 
      REFERENCED_TABLE_SCHEMA_VAR, 
      REFERENCED_TABLE_NAME_VAR, 
      REFERENCED_COLUMN_NAME_VAR; 
      IF done THEN 
       LEAVE foreign_key_cursor_loop; 
      END IF; 


      SET @from_part = CONCAT('FROM ', '`', TABLE_SCHEMA_VAR, '`.`', TABLE_NAME_VAR, '`', ' AS REFERRING ', 
       'LEFT JOIN `', REFERENCED_TABLE_SCHEMA_VAR, '`.`', REFERENCED_TABLE_NAME_VAR, '`', ' AS REFERRED ', 
       'ON (REFERRING', '.`', COLUMN_NAME_VAR, '`', ' = ', 'REFERRED', '.`', REFERENCED_COLUMN_NAME_VAR, '`', ') ', 
       'WHERE REFERRING', '.`', COLUMN_NAME_VAR, '`', ' IS NOT NULL ', 
       'AND REFERRED', '.`', REFERENCED_COLUMN_NAME_VAR, '`', ' IS NULL'); 
      SET @full_query = CONCAT('SELECT COUNT(*) ', @from_part, ' INTO @invalid_key_count;'); 
      PREPARE stmt FROM @full_query; 

      EXECUTE stmt; 
      IF @invalid_key_count > 0 THEN 
       INSERT INTO 
        INVALID_FOREIGN_KEYS 
       SET 
        `TABLE_SCHEMA` = TABLE_SCHEMA_VAR, 
        `TABLE_NAME` = TABLE_NAME_VAR, 
        `COLUMN_NAME` = COLUMN_NAME_VAR, 
        `CONSTRAINT_NAME` = CONSTRAINT_NAME_VAR, 
        `REFERENCED_TABLE_SCHEMA` = REFERENCED_TABLE_SCHEMA_VAR, 
        `REFERENCED_TABLE_NAME` = REFERENCED_TABLE_NAME_VAR, 
        `REFERENCED_COLUMN_NAME` = REFERENCED_COLUMN_NAME_VAR, 
        `INVALID_KEY_COUNT` = @invalid_key_count, 
        `INVALID_KEY_SQL` = CONCAT('SELECT ', 
         'REFERRING.', '`', COLUMN_NAME_VAR, '` ', 'AS "Invalid: ', COLUMN_NAME_VAR, '", ', 
         'REFERRING.* ', 
         @from_part, ';'), 
        `INVALID_KEY_DELETE_SQL` = CONCAT('DELETE ', '`', TABLE_SCHEMA_VAR, '`.`', TABLE_NAME_VAR, '` ', 
         'FROM ', '`', TABLE_SCHEMA_VAR, '`.`', TABLE_NAME_VAR, '`', ' ', 
         'LEFT JOIN `', REFERENCED_TABLE_SCHEMA_VAR, '`.`', REFERENCED_TABLE_NAME_VAR, '`', ' ', 
         'ON (', '`', TABLE_SCHEMA_VAR, '`.`', TABLE_NAME_VAR, '`', '.`', COLUMN_NAME_VAR, '`', ' = ', '`', REFERENCED_TABLE_SCHEMA_VAR, '`.`', REFERENCED_TABLE_NAME_VAR, '`', '.`', REFERENCED_COLUMN_NAME_VAR, '`', ') ', 
         'WHERE ', '`', TABLE_SCHEMA_VAR, '`.`', TABLE_NAME_VAR, '`', '.`', COLUMN_NAME_VAR, '`', ' IS NOT NULL ', 
         'AND ', '`', REFERENCED_TABLE_SCHEMA_VAR, '`.`', REFERENCED_TABLE_NAME_VAR, '`', '.`', REFERENCED_COLUMN_NAME_VAR, '`', ' IS NULL', ';'); 
      END IF; 
      DEALLOCATE PREPARE stmt; 

     END LOOP foreign_key_cursor_loop; 
    END$$ 

DELIMITER ; 

CALL ANALYZE_INVALID_FOREIGN_KEYS('%', '%', 'Y'); 
DROP PROCEDURE IF EXISTS ANALYZE_INVALID_FOREIGN_KEYS; 

SELECT * FROM INVALID_FOREIGN_KEYS; 
+2

मुझे पता है कि यह पुराना है लेकिन अब इस पर आया है और मैं सोच रहा हूं: किसी भी कारण से आप 'CONCAT' का उपयोग नहीं कर रहे हैं ('डिलीट रेफरिंग', @from_part, ';') 'DELETE कथन के लिए? – Likeyn

1

ही जाँच लेकिन अवैध अद्वितीय कुंजी विश्लेषण के लिए:

->छोटे बग/सुविधा: यह भी डुप्लिकेट nulls रिपोर्ट करेंगे। (जबकि mysql डुप्लिकेट नल की अनुमति देता है)।

DELIMITER $$ 

DROP PROCEDURE IF EXISTS ANALYZE_INVALID_UNIQUE_KEYS$$ 

CREATE 
    PROCEDURE `ANALYZE_INVALID_UNIQUE_KEYS`(
     checked_database_name VARCHAR(64), 
     checked_table_name VARCHAR(64)) 

    LANGUAGE SQL 
    NOT DETERMINISTIC 
    READS SQL DATA 

    BEGIN 
     DECLARE TABLE_SCHEMA_VAR VARCHAR(64); 
     DECLARE TABLE_NAME_VAR VARCHAR(64); 
     DECLARE COLUMN_NAMES_VAR VARCHAR(1000); 
     DECLARE CONSTRAINT_NAME_VAR VARCHAR(64); 

     DECLARE done INT DEFAULT 0; 

     DECLARE unique_key_cursor CURSOR FOR 
      select kcu.table_schema sch, 
        kcu.table_name tbl, 
        group_concat(kcu.column_name) colName, 
        kcu.constraint_name constName 
      from 
       information_schema.table_constraints tc 
      join 
       information_schema.key_column_usage kcu 
      on 
       kcu.constraint_name=tc.constraint_name 
       and kcu.constraint_schema=tc.constraint_schema 
       and kcu.table_name=tc.table_name 
      where 
       kcu.table_schema like checked_database_name 
       and kcu.table_name like checked_table_name 
       and tc.constraint_type="UNIQUE" group by sch, tbl, constName; 

     DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 

     DROP TEMPORARY TABLE IF EXISTS INVALID_UNIQUE_KEYS; 
     CREATE TEMPORARY TABLE INVALID_UNIQUE_KEYS(
      `TABLE_SCHEMA` VARCHAR(64), 
      `TABLE_NAME` VARCHAR(64), 
      `COLUMN_NAMES` VARCHAR(1000), 
      `CONSTRAINT_NAME` VARCHAR(64), 
      `INVALID_KEY_COUNT` INT 
     ); 



     OPEN unique_key_cursor; 
     unique_key_cursor_loop: LOOP 
      FETCH unique_key_cursor INTO 
      TABLE_SCHEMA_VAR, 
      TABLE_NAME_VAR, 
      COLUMN_NAMES_VAR, 
      CONSTRAINT_NAME_VAR; 
      IF done THEN 
       LEAVE unique_key_cursor_loop; 
      END IF; 

      SET @from_part = CONCAT('FROM (SELECT COUNT(*) counter FROM', '`', TABLE_SCHEMA_VAR, '`.`', TABLE_NAME_VAR, '`', 
        ' GROUP BY ', COLUMN_NAMES_VAR , ') as s where s.counter > 1'); 
      SET @full_query = CONCAT('SELECT COUNT(*) ', @from_part, ' INTO @invalid_key_count;'); 
      PREPARE stmt FROM @full_query; 
      EXECUTE stmt; 
      IF @invalid_key_count > 0 THEN 
       INSERT INTO 
        INVALID_UNIQUE_KEYS 
       SET 
        `TABLE_SCHEMA` = TABLE_SCHEMA_VAR, 
        `TABLE_NAME` = TABLE_NAME_VAR, 
        `COLUMN_NAMES` = COLUMN_NAMES_VAR, 
        `CONSTRAINT_NAME` = CONSTRAINT_NAME_VAR, 
        `INVALID_KEY_COUNT` = @invalid_key_count; 
      END IF; 
      DEALLOCATE PREPARE stmt; 

     END LOOP unique_key_cursor_loop; 
    END$$ 

DELIMITER ; 

CALL ANALYZE_INVALID_UNIQUE_KEYS('%', '%'); 
DROP PROCEDURE IF EXISTS ANALYZE_INVALID_UNIQUE_KEYS; 

SELECT * FROM INVALID_UNIQUE_KEYS; 
1

मैंने एकाधिक कॉलम विदेशी कुंजी को संभालने के लिए स्क्रिप्ट को संशोधित किया।

CREATE PROCEDURE `ANALYZE_INVALID_FOREIGN_KEYS`(IN `checked_database_name` VARCHAR(64), IN `checked_table_name` VARCHAR(64), IN `temporary_result_table` ENUM('Y', 'N')) 
    LANGUAGE SQL 
    NOT DETERMINISTIC 
    READS SQL DATA 
    SQL SECURITY DEFINER 
    COMMENT '' 
BEGIN 
    DECLARE TABLE_SCHEMA_VAR VARCHAR(64); 
    DECLARE TABLE_NAME_VAR VARCHAR(64); 
    DECLARE COLUMN_NAME_VAR VARCHAR(64); 
    DECLARE CONSTRAINT_NAME_VAR VARCHAR(64); 
    DECLARE REFERENCED_TABLE_SCHEMA_VAR VARCHAR(64); 
    DECLARE REFERENCED_TABLE_NAME_VAR VARCHAR(64); 
    DECLARE REFERENCED_COLUMN_NAME_VAR VARCHAR(64); 
    DECLARE KEYS_SQL_VAR VARCHAR(1024); 

    DECLARE done INT DEFAULT 0; 

    DECLARE foreign_key_cursor CURSOR FOR 
     SELECT 
      `TABLE_SCHEMA`, 
      `TABLE_NAME`, 
      `COLUMN_NAME`, 
      `CONSTRAINT_NAME`, 
      `REFERENCED_TABLE_SCHEMA`, 
      `REFERENCED_TABLE_NAME`, 
      `REFERENCED_COLUMN_NAME` 
     FROM 
      information_schema.KEY_COLUMN_USAGE 
     WHERE 
      `CONSTRAINT_SCHEMA` LIKE checked_database_name AND 
      `TABLE_NAME` LIKE checked_table_name AND 
      `REFERENCED_TABLE_SCHEMA` IS NOT NULL; 

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 

    IF temporary_result_table = 'N' THEN 
     DROP TEMPORARY TABLE IF EXISTS INVALID_FOREIGN_KEYS; 
     DROP TABLE IF EXISTS INVALID_FOREIGN_KEYS; 

     CREATE TABLE INVALID_FOREIGN_KEYS(
      `TABLE_SCHEMA` VARCHAR(64), 
      `TABLE_NAME` VARCHAR(64), 
      `COLUMN_NAME` VARCHAR(64), 
      `CONSTRAINT_NAME` VARCHAR(64), 
      `REFERENCED_TABLE_SCHEMA` VARCHAR(64), 
      `REFERENCED_TABLE_NAME` VARCHAR(64), 
      `REFERENCED_COLUMN_NAME` VARCHAR(64), 
      `INVALID_KEY_COUNT` INT, 
      `INVALID_KEY_SQL` VARCHAR(1024) 
     ); 
    ELSEIF temporary_result_table = 'Y' THEN 
     DROP TEMPORARY TABLE IF EXISTS INVALID_FOREIGN_KEYS; 
     DROP TABLE IF EXISTS INVALID_FOREIGN_KEYS; 

     CREATE TEMPORARY TABLE INVALID_FOREIGN_KEYS(
      `TABLE_SCHEMA` VARCHAR(64), 
      `TABLE_NAME` VARCHAR(64), 
      `COLUMN_NAME` VARCHAR(64), 
      `CONSTRAINT_NAME` VARCHAR(64), 
      `REFERENCED_TABLE_SCHEMA` VARCHAR(64), 
      `REFERENCED_TABLE_NAME` VARCHAR(64), 
      `REFERENCED_COLUMN_NAME` VARCHAR(64), 
      `INVALID_KEY_COUNT` INT, 
      `INVALID_KEY_SQL` VARCHAR(1024) 
     ); 
    END IF; 

    SET @prev_name = ''; 
    SET @from_part = ''; 
    SET @where_part = ''; 
    SET @where_nullable = ''; 

    OPEN foreign_key_cursor; 
    foreign_key_cursor_loop: LOOP    
     FETCH foreign_key_cursor INTO 
     TABLE_SCHEMA_VAR, 
     TABLE_NAME_VAR, 
     COLUMN_NAME_VAR, 
     CONSTRAINT_NAME_VAR, 
     REFERENCED_TABLE_SCHEMA_VAR, 
     REFERENCED_TABLE_NAME_VAR, 
     REFERENCED_COLUMN_NAME_VAR; 

     IF done THEN 
      LEAVE foreign_key_cursor_loop; 
     END IF; 

     IF (@prev_name <> CONSTRAINT_NAME_VAR AND @from_part <> '' AND @where_part <> '') THEN 

      SET @full_query = CONCAT('SELECT COUNT(*) ', @from_part, ' WHERE (', @where_nullable , ') AND ', @from_where_part, 'WHERE ', @where_part, ') INTO @invalid_key_count;'); 
      SET @invalid_query = CONCAT('SELECT * ', @from_part, ' WHERE (', @where_nullable , ') AND ', @from_where_part, 'WHERE ', @where_part, ')'); 
      PREPARE stmt FROM @full_query; 

      EXECUTE stmt; 
      IF @invalid_key_count > 0 THEN 
       INSERT INTO 
        INVALID_FOREIGN_KEYS 
       SET 
        `TABLE_SCHEMA` = TABLE_SCHEMA_VAR, 
        `TABLE_NAME` = TABLE_NAME_VAR, 
        `COLUMN_NAME` = NULL, 
        `CONSTRAINT_NAME` = CONSTRAINT_NAME_VAR, 
        `REFERENCED_TABLE_SCHEMA` = REFERENCED_TABLE_SCHEMA_VAR, 
        `REFERENCED_TABLE_NAME` = REFERENCED_TABLE_NAME_VAR, 
        `REFERENCED_COLUMN_NAME` = NULL, 
        `INVALID_KEY_COUNT` = @invalid_key_count, 
        `INVALID_KEY_SQL` = @invalid_query; 
      END IF; 
      DEALLOCATE PREPARE stmt; 

      SET @where_part = ''; 
      SET @where_nullable = ''; 
     END IF; 

     IF (LENGTH(@where_part) > 0) THEN 
      SET @where_nullable = CONCAT(@where_nullable, ' OR '); 
      SET @where_part = CONCAT(@where_part, ' AND '); 
     ELSE 
      SET @from_part = CONCAT('FROM ', '`', TABLE_SCHEMA_VAR, '`.`', 
       TABLE_NAME_VAR, '`', ' AS REFERRING '); 
      SET @from_where_part = CONCAT('NOT EXISTS (SELECT * FROM `', 
       REFERENCED_TABLE_SCHEMA_VAR, '`.`', REFERENCED_TABLE_NAME_VAR, '`', ' AS REFERRED '); 
     END IF; 

     SET @where_nullable = CONCAT(@where_nullable, 'REFERRING.', COLUMN_NAME_VAR, ' IS NOT NULL'); 
     SET @where_part = CONCAT(@where_part, 'REFERRING.', COLUMN_NAME_VAR, ' = ', 'REFERRED.', REFERENCED_COLUMN_NAME_VAR); 
     SET @prev_name = CONSTRAINT_NAME_VAR; 

    END LOOP foreign_key_cursor_loop; 

    IF (@where_part <> '' AND @from_part <> '') THEN 

     SET @full_query = CONCAT('SELECT COUNT(*) ', @from_part, ' WHERE (', @where_nullable , ') AND ', @from_where_part, 'WHERE ', @where_part, ') INTO @invalid_key_count;'); 
     SET @invalid_query = CONCAT('SELECT * ', @from_part, ' WHERE (', @where_nullable , ') AND ', @from_where_part, 'WHERE ', @where_part, ')'); 
     PREPARE stmt FROM @full_query; 

     EXECUTE stmt; 
     IF @invalid_key_count > 0 THEN 
      INSERT INTO 
       INVALID_FOREIGN_KEYS 
      SET 
       `TABLE_SCHEMA` = TABLE_SCHEMA_VAR, 
       `TABLE_NAME` = TABLE_NAME_VAR, 
       `COLUMN_NAME` = NULL, 
       `CONSTRAINT_NAME` = CONSTRAINT_NAME_VAR, 
       `REFERENCED_TABLE_SCHEMA` = REFERENCED_TABLE_SCHEMA_VAR, 
       `REFERENCED_TABLE_NAME` = REFERENCED_TABLE_NAME_VAR, 
       `REFERENCED_COLUMN_NAME` = NULL, 
       `INVALID_KEY_COUNT` = @invalid_key_count, 
       `INVALID_KEY_SQL` = @invalid_query; 
     END IF; 
     DEALLOCATE PREPARE stmt; 
    END IF; 
END 
संबंधित मुद्दे