2017-04-23 39 views
1

我試過以下內容,但由於某種原因@check參數設置爲我試圖檢查的約束的值,即使約束不存在。如何檢測是否在mysql存儲過程中添加了外鍵?

任何想法爲什麼?

CREATE PROCEDURE AddForeignKey(
    IN constraint_name varchar(64), 
    IN foreign_key_column_name varchar(64), 
    IN table_name varchar(64), 
    IN database_name varchar(64), 
    IN foreign_table_key_name varchar(64), 
    IN foreign_table_name varchar(64)) 

BEGIN 
    set @sql = CONCAT('ALTER TABLE ', database_name, '.', table_name, 
      ' ADD CONSTRAINT ', constraint_name, 
       ' FOREIGN KEY (', foreign_key_column_name, ')' 
       ' REFERENCES ', foreign_table_name, ' (', foreign_table_key_name, ');') ; 

    set @dbname = database_name; 

    set @fkname = constraint_name; 

    set @check = ''; 

    SELECT 
     CONSTRAINT_NAME 
    INTO 
     @check 
    FROM 
     INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
    WHERE 
     CONSTRAINT_SCHEMA = @dbname 
    AND 
     CONSTRAINT_NAME = @fkname 
    AND 
     CONSTRAINT_TYPE = 'FOREIGN KEY' 
    LIMIT 1; 

    IF @check != @fkname 
    THEN 
     prepare stmt from @sql; 
     execute stmt; 
    ELSE 
     insert into errors(message) values (CONCAT ('Check: ', @check, ' DB:', @dbname, ' FK:', @fkname, ' Could not execute statement: ', @sql)); 
    END IF; 
END 
+0

我無法重現該問題。請參閱[db-fiddle](https://www.db-fiddle.com/f/huwJ99DrjLbaLPqKCvcBhB/0)。 – wchiquito

+0

我沒有使用MySQL作爲root用戶。我也使用MySQL 5.6。 – rstackhouse

回答

1

你只是比較列CONSTRAINT_NAME是不足以防止外鍵重複創作。

您必須添加REFERENTIAL_CONSTRAINTS表並添加更多列進行比較。

我也改變了變量名,以避免不必要的變量名:

CREATE PROCEDURE AddForeignKey(
    IN p_constraint_name varchar(64), 
    IN foreign_key_column_name varchar(64), 
    IN p_table_name varchar(64), 
    IN p_database_name varchar(64), 
    IN foreign_table_key_name varchar(64), 
    IN foreign_table_name varchar(64)) 

BEGIN 
    set @sql = CONCAT('ALTER TABLE `', p_database_name, '`.`', p_table_name, 
     '` ADD CONSTRAINT `', p_constraint_name, 
      '` FOREIGN KEY (`', foreign_key_column_name, '`)' 
      ' REFERENCES `', foreign_table_name, '` (`', foreign_table_key_name, '`);') ; 

    set @check = ''; 

    SELECT 
     TABLE_CONSTRAINTS.CONSTRAINT_NAME 
     INTO @check 
    FROM 
    INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
      INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS 
      ON TABLE_CONSTRAINTS.CONSTRAINT_SCHEMA = REFERENTIAL_CONSTRAINTS.CONSTRAINT_SCHEMA 
       AND TABLE_CONSTRAINTS.CONSTRAINT_NAME = REFERENTIAL_CONSTRAINTS.CONSTRAINT_NAME 
       AND TABLE_CONSTRAINTS.TABLE_NAME = REFERENTIAL_CONSTRAINTS.TABLE_NAME 

    WHERE 
    TABLE_CONSTRAINTS.CONSTRAINT_SCHEMA = p_database_name 
     AND TABLE_CONSTRAINTS.CONSTRAINT_NAME = p_constraint_name 
     AND TABLE_CONSTRAINTS.CONSTRAINT_TYPE = 'FOREIGN KEY' 
    AND TABLE_CONSTRAINTS.TABLE_NAME = p_table_name 
     and REFERENTIAL_CONSTRAINTS.REFERENCED_TABLE_NAME = foreign_table_name 
    LIMIT 1; 

    IF @check <> p_constraint_name 
    THEN 
     prepare stmt from @sql; 
     execute stmt; 
    ELSE 
     insert into errors(message) values (CONCAT ('Check: ', @check, ' DB:', @dbname, ' FK:', 
     @fkname, ' Could not execute statement: ', @sql)); 
    END IF; 

END 
+0

我不相信你已經回答了我的問題。我會做出你所建議的改變,看看是否有什麼影響,但我懷疑它。你對terser SQL和更徹底的檢查有公平的觀點,但這些並不是我遇到的問題。另外,在ELSE條件下插入將失敗。 – rstackhouse

+0

告訴我如果在測試我的答案後解決您的問題 –

+0

不太確定如何,但這似乎已修復它。 – rstackhouse