2012-12-13 4 views
8

Se una chiave esterna è stata creata senza un nome, MySql ne assegnerà una predefinita. Ad esempio, per la tabella 'Test' la chiave esterna sarà denominata 'test_ibfk_1'. Quando faccio cadere la chiave esterna localmente usando questo nome funziona come un incantesimo ma sul server di sviluppo fallisce con errno: 152.Elimina chiave esterna senza nome in MySql

So che questo nome è case sensitive ma sia in lettere maiuscole che maiuscole il risultato è lo stesso .

La mia domanda: è sicuro fare affidamento sul nome predefinito per manipolare i vincoli (almeno in MySql)?

Grazie in anticipo!

risposta

14

È necessario conoscere il nome della chiave esterna. Se è stato creato senza nome, il nome verrà generato automaticamente. Dovresti ottenere informazioni sulla chiave esterna.

Utilizzare una di queste query per ottenere i nomi di chiave esterna -

SELECT 
    constraint_name 
FROM 
    information_schema.REFERENTIAL_CONSTRAINTS 
WHERE 
    constraint_schema = <'db_name'> AND table_name = <'table_name'>; 


SELECT * 
FROM 
    information_schema.KEY_COLUMN_USAGE 
WHERE 
    constraint_schema = <'db_name'> AND table_name = <'table_name'> AND 
    referenced_table_name IS NOT NULL; 

... e utilizzare ALTER TABLE <table_name> DROP INDEX <fk_name>; a goccia chiave esterna.

+0

La query precedente è applicabile ai non amministratori? Nel complesso molto buono per sapere informazioni! Grazie! –

+5

È un peccato dover passare attraverso questo viaggio di resistenza, solo per ottenere il tuo nome_fk per questo tipo di query. Dovrebbe essere semplice dire: 'ALTER tabella nome_tabella DROP CONSTRAINT ON col_name' (indipendentemente dal nome che porta). Dopotutto, ci può essere solo uno di questi vincoli su una data chiave. Giusto a tutti? –

+1

@IfediOkonkwo, sono completamente d'accordo. È particolarmente problematico se si utilizza qualcosa come Liquibase per gestire le modifiche dello schema nei database di più ambienti e non è garantito che generi lo stesso nome del vincolo FK su ogni database su cui vengono eseguiti. Ciò significa che non puoi fare affidamento su quel nome di vincolo nelle future modifiche. Sebbene tu possa ovviamente iniziare a nominare i vincoli con un nome fisso dall'inizio. –

3

Si potrebbe rimuovere senza conoscere il nome, la creazione di una query concatena e l'esecuzione automatica:

set @s:=''; 
select @s:=concat(@s, 'alter table ', 'your_table', ' drop foreign key ',CONSTRAINT_NAME, ';') 
from information_schema.key_column_usage 
where CONSTRAINT_SCHEMA = 'your_database' 
    and TABLE_NAME ='your_table' 
    and REFERENCED_TABLE_NAME = 'the_foreign_reference_table'; 
prepare stmt from @s; 
execute stmt; 

deallocate prepare stmt; 

io in questo modo non è necessario conoscere il nome della chiave esterna, solo bisogno nome_tabella cui si desidera rimuovere la chiave esterna, il nome del database e la tabella di riferimento.

0

Lettore frettoloso, non andare via da questa risposta, solo perché è lunga. Non troverai un'altra soluzione, prometto :)

La risposta accettata non rilascia la chiave, trova solo il suo nome. Per rilasciare effettivamente la chiave con un nome sconosciuto, è necessario utilizzare istruzioni preparate. La soluzione più generale è questo script che è possibile personalizzare con cinque variabili:

-- YOU MUST SPECIFY THESE VARIABLES TO FULLY IDENTIFY A CONSTRAINT 
SET @table_name = '...'; 
SET @column_name = '...'; 
SET @referenced_table_name = '...'; 
SET @referenced_column_name = '...'; 
-- make sure to limit queries to a single db schema 
SET @db_name = '...'; 

-- find the name of the foreign key and store it in a var 
SET @constraint_name = (
    SELECT constraint_name 
    FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE 
    WHERE TABLE_NAME = @table_name 
     AND COLUMN_NAME = @column_name 
     AND CONSTRAINT_SCHEMA = @db_name 
     AND referenced_table_name = @referenced_table_name 
     AND referenced_column_name = @referenced_column_name); 


-- prepare the drop statement in a string and run it 
SET @s = concat('alter table ', @table_name, ' drop foreign key ', @constraint_name); 

PREPARE stmt FROM @s; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt;