17

私は MySQL を使用しており、他の多くのテーブルで外部キーとして使用されるインデックスを持つテーブルがあります。インデックスのデータ型を (符号付きから符号なし整数に) 変更したいのですが、これを行う最善の方法は何ですか?

インデックス フィールドのデータ型を変更しようとしましたが、他のテーブルの外部キーとして使用されているため失敗します。外部キーの 1 つでデータ型を変更しようとしましたが、インデックスのデータ型と一致しなかったため失敗しました。

すべての外部キー制約を手動で削除し、データ型を変更して制約を追加し直すことができると思いますが、このインデックスを外部キーとして使用するテーブルがたくさんあるため、これは大変な作業になります。変更中に外部キー制約を一時的にオフにする方法はありますか? また、インデックスを外部キーとして参照しているすべてのフィールドのリストを取得する方法はありますか?

更新: 外部キーのチェックをオフにした後、1 つの外部キーを変更しようとしましたが、チェックをオフにしていないようです:

SET foreign_key_checks = 0;

ALTER TABLE `escolaterrafir`.`t23_aluno` MODIFY COLUMN `a21_saida_id` INTEGER DEFAULT NULL;

エラーは次のとおりです。

------------------------
LATEST FOREIGN KEY ERROR
------------------------
090506 11:57:34 Error in foreign key constraint of table escolaterrafir/t23_aluno:
there is no index in the table which would contain
the columns as the first columns, or the data types in the
table do not match to the ones in the referenced table
or one of the ON ... SET NULL columns is declared NOT NULL. Constraint:
,
  CONSTRAINT FK_t23_aluno_8 FOREIGN KEY (a21_saida_id) REFERENCES t21_turma (A21_ID)

インデックス テーブルの定義:

DROP TABLE IF EXISTS `escolaterrafir`.`t21_turma`;
CREATE TABLE  `escolaterrafir`.`t21_turma` (
  `A21_ID` int(10) unsigned NOT NULL auto_increment,
  ...
) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=latin1;

そして、それを指す外部キーを持つテーブル:

DROP TABLE IF EXISTS `escolaterrafir`.`t23_aluno`;
CREATE TABLE  `escolaterrafir`.`t23_aluno` (
  ...
  `a21_saida_id` int(10) unsigned default NULL,
  ...
  KEY `Index_7` (`a23_id_pedagogica`),
  ...
  CONSTRAINT `FK_t23_aluno_8` FOREIGN KEY (`a21_saida_id`) REFERENCES `t21_turma` (`A21_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=387 DEFAULT CHARSET=latin1;
4

7 に答える 7

18

これが、このスレッドへの私のささやかな貢献です。Daniel Schneller にインスピレーションを与え、解決策の大部分を与えてくれたことに感謝します!

set group_concat_max_len = 2048;
set @table_name = "YourTableName";
set @change = "bigint unsigned";
select distinct table_name,
       column_name,
       constraint_name,
       referenced_table_name,
       referenced_column_name,
       CONCAT(
           GROUP_CONCAT('ALTER TABLE ',table_name,' DROP FOREIGN KEY ',constraint_name SEPARATOR ';'),
           ';',
           GROUP_CONCAT('ALTER TABLE `',table_name,'` CHANGE `',column_name,'` `',column_name,'` ',@change SEPARATOR ';'),
           ';',
           CONCAT('ALTER TABLE `',@table_name,'` CHANGE `',referenced_column_name,'` `',referenced_column_name,'` ',@change),
           ';',
           GROUP_CONCAT('ALTER TABLE `',table_name,'` ADD CONSTRAINT `',constraint_name,'` FOREIGN KEY(',column_name,') REFERENCES ',referenced_table_name,'(',referenced_column_name,')' SEPARATOR ';')
       ) as query
from   INFORMATION_SCHEMA.key_column_usage
where  referenced_table_name is not null
   and referenced_column_name is not null
   and referenced_table_name = @table_name
group by referenced_table_name

@table_name と @change を設定すると、クエリを生成できます。@table_name は、主キーを持つテーブルのテーブル名である必要があり (その列を外部キーとして使用するテーブルを検索します)、そのタイプを @change に変更します。

そのようないくつかのテーブルを変更する必要があったので、それは魅力のように機能しました. @table_name を変更してからクエリを実行するだけでした。

于 2011-02-22T12:04:37.777 に答える
14

私自身の質問に答えるために、これを行うためのより簡単な方法を見つけることができませんでした. 最終的に、すべての外部キー制約を削除し、フィールド タイプを変更してから、すべての外部キー制約を追加し直しました。

R. Bemrose が指摘したように、使用SET foreign_key_checks = 0;はデータを追加または変更する場合にのみ役立ちますが、ALTER TABLE外部キーの制約を破るコマンドは許可されません。

于 2009-05-12T17:05:27.703 に答える
2

データベースを停止できる場合は、テーブルをテキストファイルにダンプし、ファイル内の列定義を手動で変更して、テーブルをインポートして戻します。

于 2010-02-03T10:27:36.277 に答える
2

外部キー制約の使用について調べるには、INFORMATION_SCHEMAデータベースで次のクエリを発行します。

select distinct table_name, 
       column_name, 
       constraint_name,  
       referenced_table_name, 
       referenced_column_name 
from   key_column_usage 
where  constraint_schema = 'XXX' 
   and referenced_table_name is not null 
   and referenced_column_name is not null;

XXXスキーマ名に置き換えます。これにより、他の列を外部キーとして参照するテーブルと列のリストが得られます。

残念ながら、スキーマの変更は非トランザクションであるため、この操作のためにforeign_key_checksを一時的に無効にする必要があるのではないかと心配しています. 偶発的な制約違反のリスクを最小限に抑えるために、可能であれば、このフェーズ中にクライアントからの接続を防止することをお勧めします。

キー自体については、テーブルのデータ型を変更したときに、それらを削除して再作成する必要があります。

于 2009-05-06T15:04:12.067 に答える
1

次のように入力して、外部キーを一時的に無効にすることができます

SET foreign_key_checks = 0;

それらを再度有効にするには

SET foreign_key_checks = 1;

データベースにデータをインポートすることを目的としているため、これには管理者権限が必要だと思います。

編集:編集に応じて、DML ステートメント (挿入、更新、削除) の制約のみを無効にしているように見えますが、DDL ステートメント (テーブルの変更、テーブルの削除など) は無効にしないようです。

于 2009-05-06T14:48:15.443 に答える
1

ここにも、このスレッドへの私の小さな貢献があります。Daniel Schneller と Wiktor Jarka にインスピレーションを与え、解決策の大部分を与えてくれたことに感謝します! このソリューションは、データベースと自動インクリメントの問題を修正します。

SET group_concat_max_len = 2048;
SET @database_name = "my_database";
SET @table_name = "my_table";
SET @change = "tinyint unsigned";
SELECT DISTINCT 
       `table_name`,
       `column_name`,
       `constraint_name`,
       `referenced_table_name`,
       `referenced_column_name`,
       CONCAT(
           GROUP_CONCAT('ALTER TABLE `',table_name,'` DROP FOREIGN KEY `',constraint_name, '`' SEPARATOR ';'),
           ';',
           GROUP_CONCAT('ALTER TABLE `',table_name,'` CHANGE `',column_name,'` `',column_name,'` ',@change SEPARATOR ';'),
           ';',
           CONCAT('ALTER TABLE `',@table_name,'` CHANGE `',referenced_column_name,'` `',referenced_column_name,'` ',@change, ' NOT NULL AUTO_INCREMENT'),
           ';',
           GROUP_CONCAT('ALTER TABLE `',table_name,'` ADD CONSTRAINT `',constraint_name,'` FOREIGN KEY(',column_name,') REFERENCES ',referenced_table_name,'(',referenced_column_name,')' SEPARATOR ';'), 
           ';'
       ) AS query
FROM   `information_schema`.`key_column_usage`
WHERE  `referenced_table_name` IS NOT NULL
   AND `referenced_column_name` IS NOT NULL
   AND `constraint_schema` = @database_name
   AND `referenced_table_name` = @table_name
GROUP BY `referenced_table_name`
于 2020-05-08T18:28:33.693 に答える