On Thu, Jan 03, 2002 at 05:21:49PM +0200, Heikki Tuuri wrote:
: mysql> CREATE TABLE parent(id INT NOT NULL, PRIMARY KEY (id)) TYPE=INNODB;
: Query OK, 0 rows affected (0.11 sec)
: 
: mysql> CREATE TABLE child(id INT, parent_id INT, INDEX par_ind (parent_id),
:     ->                   FOREIGN KEY (parent_id) REFERENCES parent(id))
: TYPE=INN
: ODB;
: Query OK, 0 rows affected (0.03 sec)
: 
: mysql> insert into parent values (10);
: Query OK, 1 row affected (0.00 sec)
: 
: mysql> insert into child values (5, 10);
: Query OK, 1 row affected (0.00 sec)
: 
: mysql> drop table parent;
: Query OK, 0 rows affected (0.01 sec)
: 
: mysql> CREATE TABLE parent(id INT NOT NULL, PRIMARY KEY (id)) TYPE=INNODB;
: Query OK, 0 rows affected (0.01 sec)
: 
: mysql> insert into parent values (10);
: Query OK, 1 row affected (0.00 sec)
: 
: mysql> insert into parent values (20);
: Query OK, 1 row affected (0.01 sec)
: 
: mysql> insert into child values (6, 20);
: Query OK, 1 row affected (0.00 sec)

Well, the problem right here with this methodology is that if parent
is a large table, you have to reinsert all the data back into that
table.  That may be fine for small tables, but for 100,000 to
1,000,000+ row tables, that's pretty annoying.

So we make a copy of our data first, so that the reinsertion goes
much easier.  I do this by simply renaming the table to get it out
of the way.  Then I make my new table with the same name as my old
one, insert into it out of my old (renamed) table and then drop
the renamed.  Thus, I'm sure my data is correct.

The problem appears to be that the child foreign key follows it's
parent table around even after the rename, so when I create my new
table with the same name as the old one, the child is no longer
pointing there.  On first thought, I would expect the child not to
follow on a rename (because of the explicit pointer to a table
named 'parent').  On the flip-side, I can see how it might be
beneficial, but foreign keys in the abstract sense are references
to keys by table names, not references to keys by table object.

Using this methodology (listed below) should be significantly faster
if you want to preserve the data in your table.  Using the method
you detailed, if you wanted to preserve the contents of the table
being altered, you'd first have to dump your data into a file or
another temporary table, then reinsert it.

As an aside, the reverse method of this (create the new table,
populate it with data from the old table, drop the old table, rename
the new table) also fails on a foreign key constraint.

mysql> create table parent( id INT NOT NULL, PRIMARY KEY (id)) TYPE=InnoDB;
Query OK, 0 rows affected (0.02 sec)

mysql> create table child( id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN 
KEY (parent_id) REFERENCES parent(id));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into parent values (10);
Query OK, 1 row affected (0.00 sec)

mysql> insert into child values (5, 10);
Query OK, 1 row affected (0.00 sec)

mysql> alter table parent rename parent_temp;
Query OK, 0 rows affected (0.02 sec)

mysql> create table parent( id INT NOT NULL, id2 INT NOT NULL, PRIMARY KEY (id)) 
TYPE=InnoDB;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into parent select id, 0 FROM parent_temp;
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> drop table parent_temp;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into parent values (20, 0); 
Query OK, 1 row affected (0.00 sec)

mysql> insert into child values (6,20);
ERROR 1216: Cannot add a child row: a foreign key constraint fails
mysql> select * from parent;
+----+-----+
| id | id2 |
+----+-----+
| 10 |   0 |
| 20 |   0 |
+----+-----+
2 rows in set (0.00 sec)

mysql> select * from child;
+------+-----------+
| id   | parent_id |
+------+-----------+
|    5 |        10 |
+------+-----------+
1 row in set (0.00 sec)

* Philip Molter
* Texas.net Internet
* http://www.texas.net/
* [EMAIL PROTECTED]

---------------------------------------------------------------------
Before posting, please check:
   http://www.mysql.com/manual.php   (the manual)
   http://lists.mysql.com/           (the list archive)

To request this thread, e-mail <[EMAIL PROTECTED]>
To unsubscribe, e-mail <[EMAIL PROTECTED]>
Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php

Reply via email to