web-dev-qa-db-fra.com

Impossible de créer une table, mais la table n'existe pas

J'utilise ces étapes pour créer une table my_user, qui existait déjà mais qui a en quelque sorte disparu de ma base de données my_db:

mysql> USE my_db;
mysql> DROP TABLE my_user;
mysql> ERROR 1051 (42S02): Unknown table 'my_user'
mysql> CREATE TABLE my_user (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(255), group_id VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
mysql> ERROR 1005 (HY000): Can't create table 'my_db.my_user' (errno: -1)

A essayé # mysqladmin flush-tables et a répété les étapes ci-dessus mais cela n'a pas été utile. En outre, redémarré le service mysql, mais pas bon.

Des idées? Google m'a échoué jusqu'à présent. Merci.

Informaitons supplémentaires:

mysql> SHOW engine innodb STATUS;
------------------------
LATEST FOREIGN KEY ERROR
------------------------
140703 15:15:09 Error in foreign key constraint of table my_db/my_user
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 the ones in the referenced table
or one of the ON ... SET NULL columns is declared NOT NULL. Constraint:
,
  CONSTRAINT "FK_CFBD431E285FAC6D" FOREIGN KEY ("group_id") REFERENCES "my_group" ("id")
11
noisebleed

Architecture InnoDB

InnoDB Architecture

UNE ANALYSE

  • D'une manière ou d'une autre, vous avez perdu le my_user.frm et my_user.ibd des dossiers. Le dictionnaire de données a toujours une entrée pour cette table.
  • Vous ne pouvez pas courir DROP TABLE my_user; parce que mysqld recherche le my_user.frm première. Puisque ce n'est pas my_user.frm, la table ne peut pas être supprimée.
  • Bien que my_user.frm n'existe pas, vous ne pouvez pas exécuter CREATE TABLE my_user ... parce que mysqld pense qu'il est OK de créer la table mais passe ensuite au moteur de stockage. InnoDB dit "J'ai déjà enregistré le tablespace_id de my_user".

Cette séquence d'événements peut être prouvée si vous créez la table à l'aide de MyISAM. mysqld le permettra. Une fois que vous passez à InnoDB, il revient directement au dictionnaire de données, qui est défectueux sur cette seule entrée.

J'ai deux suggestions

SUGGESTION # 1

Ne créez plus la table avec ce nom. Utilisez un nom de table différent

CREATE TABLE my_usertable (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(255), group_id VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;

Cela vous amènera à changer le nom de la table dans votre code d'application

SUGGESTION # 2

J'ai déjà traité ce problème dans mon article la table InnoDB SELECT renvoie ERREUR 2006 (HY000): le serveur MySQL est parti (après une panne de courant)

6
RolandoMySQLDBA

Juste pour ajouter ma solution car j'ai eu un problème similaire.

TL; DR

  • Recréez la table avec la même spécification de clé étrangère mais avec un nom différent de celui détenu précédemment par la table.
  • Supprimez la table résultante (supprimera également la clé étrangère orpheline d'origine)
  • Recréer une table avec une clé étrangère originale ou sans clé étrangère

Détail

J'ai rencontré la situation désagréable où une instruction ALTER TABLE a échoué car une clé étrangère n'a pas été supprimée plus tôt. Cela a conduit à des incohérences dans le dictionnaire de données InnoDB (probablement en raison de http://bugs.mysql.com/bug.php?id=58215 ).

Question connexe ici: https://stackoverflow.com/questions/16857451/error-in-foreign-key-constraint-on-a-droped-table

mysql> ALTER TABLE `visits` CHANGE COLUMN `variation_visitor_id` `variation_visitor_id` INT(11) NOT NULL  ;

Erreur lors du renommage de './db/#sql-482c_8448f' en './db/visits' (errno: 150)

mysql> SHOW ENGINE INNODB STATUS;

Error in foreign key constraint of table db/visits:
 FOREIGN KEY (`variation_visitor_id`) REFERENCES `variations_visitors` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
See http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html 
for correct foreign key definitippon.

Comme je n'ai pas pu récupérer la table # sql-482c_8448f aux visites, j'ai décidé de la réimporter à partir d'une sauvegarde effectuée juste avant la modification. Mais cela a échoué. Enquête:

  • La contrainte a été supprimée de INFORMATION_SCHEMA.TABLE_CONSTRAINTS et INFORMATION_SCHEMA.STATISTICS
  • Mais la contrainte était toujours visible dans INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
  • La table n'existait pas, je n'ai donc pas pu supprimer la clé étrangère
  • Je n'ai pas pu créer la table sans erreur

SQL/Erreurs

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN WHERE ID='db/fk_visits_variations_visitors1';

+-----------------------------------+-----------+------------------------+--------+------+
| ID                                | FOR_NAME  | REF_NAME               | N_COLS | TYPE |
+-----------------------------------+-----------+------------------------+--------+------+
| db/fk_visits_variations_visitors1 | db/visits | db/variations_visitors |      1 |   48 |
+-----------------------------------+-----------+------------------------+--------+------+

La tentative de recréation de la table sans la clé étrangère a provoqué une erreur 150

mysql>

SET UNIQUE_CHECKS = 0;
SET FOREIGN_KEY_CHECKS = 0;

CREATE TABLE `visits` (
  `id` INT(11) NOT NULL AUTO_INCREMENT  ,
  `variation_visitor_id` INT(11) NOT NULL  ,
  PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

SET FOREIGN_KEY_CHECKS = 1;
SET UNIQUE_CHECKS = 1;

ERROR 1005 (HY000) at line 26: Can't create table 'db.visits' (errno: 150)

mysql> SHOW ENGINE INNODB STATUS;

Error in foreign key constraint of table db/visits:
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 the ones in the referenced table
or one of the ON ... SET NULL columns is declared NOT NULL. Constraint:
,
  CONSTRAINT "fk_visits_variations_visitors1" FOREIGN KEY ("variation_visitor_id") REFERENCES "variations_visitors" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION

Essayer de le créer avec a provoqué une erreur 121

mysql>

SET UNIQUE_CHECKS = 0;
SET FOREIGN_KEY_CHECKS = 0;

CREATE TABLE `visits` (
  `id` INT(11) NOT NULL AUTO_INCREMENT  ,
  `variation_visitor_id` INT(11) NOT NULL  ,
  PRIMARY KEY (`id`),
  KEY `fk_visits_variations_visitors1` (`variation_visitor_id`),
  CONSTRAINT `fk_visits_variations_visitors1` FOREIGN KEY (`variation_visitor_id`) REFERENCES `variations_visitors` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

SET FOREIGN_KEY_CHECKS = 1;
SET UNIQUE_CHECKS = 1;

ERROR 1005 (HY000) at line 26: Can't create table 'db.visits' (errno: 121)

mysql> SHOW ENGINE INNODB STATUS;

Error in foreign key constraint creation for table `db`.`visits`.
A foreign key constraint of name `db`.`fk_visits_variations_visitors1`
already exists. (Note that internally InnoDB adds 'databasename'
in front of the user-defined constraint name.)
Note that InnoDB's FOREIGN KEY system tables store
constraint names as case-insensitive, with the
MySQL standard latin1_swedish_ci collation. If you
create tables or databases whose names differ only in
> the character case, then collisions in constraint
names can occur. Workaround: name your constraints
explicitly with unique names.

Finalement, j'ai utilisé un nouveau nom de clé étrangère. Je ne m'attendais pas à ce que cela fonctionne, mais cela a permis de créer la table.

mysql>

SET UNIQUE_CHECKS = 0;
SET FOREIGN_KEY_CHECKS = 0;

CREATE TABLE `visits` (
  `id` INT(11) NOT NULL AUTO_INCREMENT  ,
  `variation_visitor_id` INT(11) NOT NULL  ,
  PRIMARY KEY (`id`),
  KEY `fk_visits_variations_visitors2` (`variation_visitor_id`),
  CONSTRAINT `fk_visits_variations_visitors2` FOREIGN KEY (`variation_visitor_id`) REFERENCES `variations_visitors` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

SET FOREIGN_KEY_CHECKS = 1;
SET UNIQUE_CHECKS = 1;

Il suffit de supprimer la table après avoir supprimé l'enregistrement erroné dans INFORMATION_SCHEMA.INNODB_SYS_FOREIGN, permettant une importation avec le nom de clé étrangère d'origine.

5
Mark C

Il existe un moyen simple de contourner ce problème, mais il est vrai que dans certaines circonstances, vous ne voudrez peut-être pas le faire. Étant donné que ce problème provient d'une référence interne InnoDB, vous pouvez simplement créer cette table avec le même nom, les mêmes colonnes, uniquement en utilisant un moteur de stockage différent. J'ai rencontré cela sur un esclave MySQL, et même si le maître à partir duquel je répliquais était InnoDB, j'ai recréé cette seule table avec MyISAM et j'ai pu me remettre en marche. J'ai spécifiquement choisi InnoDB pour mon moteur de stockage sur le maître, et sur certaines tables, ce serait également important pour l'esclave, mais dans ce cas, cela n'a eu aucun impact sur cet esclave pour cette seule table, donc c'était un moyen rapide pour contourner ce problème. Supprimer toute la base de données aurait été un projet beaucoup plus important.

1

Ce qui a fonctionné pour moi, c'est:

  • déplacez d'abord les fichiers .frm et .ibd dans un autre répertoire, par ex./tmp/tablebackup *
  • extrait maintenant la structure de la table du fichier .frm à l'aide de mysqlfrm d'Oracle mysql-utitilies ** (car je n'avais pas d'autre copie/sauvegarde de la structure) par exemple: /usr/bin/mysqlfrm --diagnostic /tmp/tablebackup/MyTable.frm
  • créer une nouvelle table avec la structure de la table d'origine mais avec un nom différent (par exemple, disons que la table avec le problème est MyTable puis j'ai maintenant créé une table MyTableB avec la structure de la table d'origine)
  • renommer ensuite la table avec le nom d'origine depuis mysql, par exemple: RENAME TABLE `MyTableB` TO `MyTable`; (notez que cela ne fonctionne que si vous pas avez innodb_force_recovery insérez votre my.cnf)
  • maintenant dans mysql run: ALTER TABLE `MyTable` DISCARD TABLESPACE;
  • puis copiez l'original .ibd fichier (uniquement le fichier .ibd, pas le fichier .frm) dans le répertoire de la base de données mysql d'où il a été initialement déplacé (il ne devrait pas y en avoir ' t être un fichier .ibd existant en ce moment car il est supprimé par le DISCARD TABLESPACE commande)
  • et exécutez maintenant ALTER TABLE `MyTable` IMPORT TABLESPACE;

* J'ai redémarré mysql après cette étape mais je ne suis pas sûr que cela soit nécessaire

** les utilitaires mysql peuvent nécessiter l'installation mysql-connector-python d'abord

0
Arthur

Vous avez perdu les données de la table, mais l'enregistrement sur cette table existe toujours dans "mysql/data/ibdata1". La solution la plus simple consiste à créer cette table dans une autre base de données, puis à copier des fichiers:

mysql/data/**dummy_database**/my_user.frm

mysql/data/**dummy_database**/my_user.ibd

à vous:

mysql/data/**yours_database**/my_user.frm

mysql/data/**yours_database**/my_user.ibd
0
Hevyweb