i'm having trouble with some tables here.
i have this table:
CREATE TABLE `smenuitem` (
`nome` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`url` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`tipo` CHAR(4) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`ordemmenu` INT(10) NULL DEFAULT NULL,
`codparent` INT(10) UNSIGNED NOT NULL,
`codmenuitem` INT(10) UNSIGNED NOT NULL,
`codmodulo` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`codmodulo`, `codmenuitem`, `codmenuitem2`),
CONSTRAINT `FK_smenuitem_smodulos` FOREIGN KEY (`codmodulo`) REFERENCES `smodulos` (`codmodulo`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
And an second one:
CREATE TABLE `smenuitememp` (
`codempresa` INT(10) UNSIGNED NOT NULL,
`codmodulo` INT(10) UNSIGNED NOT NULL,
`codmenuitem` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`codmenuitem`, `codempresa`, `codmodulo`)
)
COLLATE='utf8_unicode_ci'
My problem it's i need to make an FK between codmenuitem
i have this sql command that are resulting on an error:
ALTER TABLE `smenuitememp` ADD CONSTRAINT `FK_smenuitememp_smenuitem` FOREIGN KEY (`codmenuitem`) REFERENCES `smenuitem` (`codmenuitem`);
When i try to execute it's return this error:
Someone has an idea?
Update... i was trying to solve the problem, and got an new question... T_T
CREATE TABLE `smenuitem` (
`nome` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`url` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`tipo` CHAR(4) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`ordemmenu` INT(10) NULL DEFAULT NULL,
`codparent` INT(10) UNSIGNED NOT NULL,
`codmenuitem` INT(10) UNSIGNED NOT NULL,
`codmodulo` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`codmodulo`, `codmenuitem`),
INDEX `codmenuitem` (`codmenuitem`),
CONSTRAINT `FK_smenuitem_smodulos` FOREIGN KEY (`codmodulo`) REFERENCES `smodulos` (`codmodulo`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
I solved the problem creating an index at the main table. But i don't know why i was having trouble without this index. If someone could ask me i would apreciate!
The foreign key column(s) must reference column(s) comprising a left-most prefix of the primary key or a unique key in the parent table.
In other words, the following examples work in InnoDB:
CREATE TABLE Foo ( a INT, b INT, c INT, PRIMARY KEY (a,b,c) );
CREATE TABLE Bar ( x INT, y INT );
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(b,c); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(a,c); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(a,b); -- RIGHT
ALTER TABLE Bar ADD FOREIGN KEY (x) REFERENCES Foo(b); -- WRONG
ALTER TABLE Bar ADD FOREIGN KEY (x) REFERENCES Foo(a); -- RIGHT
You got an error because you're trying to do the equivalent of (x) references Foo(b).
Your column codmenuitem is the second of three columns in the primary key of the parent.
It would work if smenuitememp.codemenuitem were to reference smenuitem.codmodulo, because that column is the leftmost column in the parent table's primary key.
Re your followup question:
Keep in mind the way foreign keys work. Every time you insert or update a row in the child table, it needs to look up a row in the parent table to verify that the value exists in the referenced column. If the column isn't indexed, it'll have to do a table-scan to achieve this lookup, and that would be very expensive, assuming your parent table grows.
If you try to look up a row based on the middle column of a multi-column index, the index doesn't help you. By analogy, it's like searching a telephone book for all people with a certain middle name.
Standard ANSI SQL requires that the referenced column be part of a PRIMARY KEY or UNIQUE KEY, and it requires that the foreign key columns match all the columns of a primary or unique constraint in the parent.
But InnoDB is more permissive. It still requires that the referenced column in the parent table be indexed so the lookup can be efficient, and that the referenced columns be the leftmost in the index. But a non-unique index is okay; it's allowed for a foreign key to reference it.
This can lead to weird cases like a child row that references more than one row in the parent, but it's expected that you will handle such anomalies.
I feel the need to emphasize the last point. You will get anomalous data if you define foreign keys to non-uniquely indexed columns in the parent. This will probably cause your queries to report rows multiple time when you do joins. You should not use this behavior of InnoDB; you should define foreign keys only to parent columns that are unique.
Related
When I execute the follow two queries (I have stripped them down to absolutely necessary):
mysql> CREATE TABLE foo(id INT PRIMARY KEY);
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE bar ( id INT, ref INT, FOREIGN KEY (ref) REFERENCES foo(id)) ENGINE InnoDB;
I get the following error:
ERROR 1005 (HY000): Can't create table './test/bar.frm' (errno: 150)
Where the **** is my error? I haven't found him while staring at this for half an hour.
From FOREIGN KEY Constraints
If you re-create a table that was
dropped, it must have a definition
that conforms to the foreign key
constraints referencing it. It must
have the right column names and types,
and it must have indexes on the
referenced keys, as stated earlier. If
these are not satisfied, MySQL returns
error number 1005 and refers to error
150 in the error message.
My suspicion is that it's because you didn't create foo as InnoDB, as everything else looks OK.
Edit: from the same page -
Both tables must be InnoDB tables and they must not be TEMPORARY tables.
You can use the command SHOW ENGINE INNODB STATUS to get more specific information about the error.
It will give you a result with a Status column containing a lot of text.
Look for the section called LATEST FOREIGN KEY ERROR which could for example look like this:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
190215 11:51:26 Error in foreign key constraint of table `mydb1`.`contacts`:
Create table `mydb1`.`contacts` with foreign key constraint failed. You have defined a SET NULL condition but column 'domain_id' is defined as NOT NULL in ' FOREIGN KEY (domain_id) REFERENCES domains (id) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT contacts_teams_id_fk FOREIGN KEY (team_id) REFERENCES teams (id) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT' near ' ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT contacts_teams_id_fk FOREIGN KEY (team_id) REFERENCES teams (id) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT'.
To create a foreign key ,
both the main column and the reference column must have same definition.
both tables engine must be InnoDB.
You can alter the engine of table using this command , please take the backup before executing this command.
alter table [table name] ENGINE=InnoDB;
I had the same problem, for those who are having this also:
check the table name of the referenced table
I had forgotten the 's' at the end of my table name
eg table Client --> Clients
:)
Apart form many other reasons to end up with MySql Error 150 (while using InnoDB), One of the probable reason, is the undefined KEY in the create statement of the table containing the column name referenced as a foreign key in the relative table.
Let's say the create statement of master table is -
CREATE TABLE 'master_table' (
'id' int(10) NOT NULL AUTO_INCREMENT,
'record_id' char(10) NOT NULL,
'name' varchar(50) NOT NULL DEFAULT '',
'address' varchar(200) NOT NULL DEFAULT '',
PRIMARY KEY ('id')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
and the create syntax for the relative_table table where the foreign key constraint is set from primary table -
CREATE TABLE 'relative_table' (
'id' int(10) NOT NULL AUTO_INCREMENT,
'salary' int(10) NOT NULL DEFAULT '',
'grade' char(2) NOT NULL DEFAULT '',
'record_id' char(10) DEFAULT NULL,
PRIMARY KEY ('id'),
CONSTRAINT 'fk_slave_master' FOREIGN KEY ('record_id') REFERENCES 'master' ('record_id')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This script is definitely going to end with MySql Error 150 if using InnoDB.
To solve this, we need to add a KEY for the The column record_id in the master_table table and then reference in the relative_table table to be used as a foreign_key.
Finally, the create statement for the master_table, will be -
CREATE TABLE 'master_table' (
'id' int(10) NOT NULL AUTO_INCREMENT,
'record_id' char(10) NOT NULL,
'name' varchar(50) NOT NULL DEFAULT '',
'address' varchar(200) NOT NULL DEFAULT '',
PRIMARY KEY ('id'),
KEY 'record_id' ('record_id')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I had very same problem and the reason was the "collation" of columns was different. One was latin1 while the other was utf8
This may also happen if you have not given correct column name after "references" keyword.
shippings table structure
I want to connect in to another table like this(I got "1215 error"):
CREATE TABLE goods_and_shippings (
good_id INT NOT NULL,
s_date DATE NOT NULL,
shipping_id INT NOT NULL,
PRIMARY KEY (good_id),
FOREIGN KEY (s_date) REFERENCES shippings(s_date)
)
Connected columns have same data types as you can see (both DATE and NOT NULL) and all tables use InnoDB engine. But I have this snippet and it works:
CREATE TABLE goods_and_shippings (
good_id INT NOT NULL,
s_date DATE NOT NULL,
shipping_id INT NOT NULL,
PRIMARY KEY (good_id),
FOREIGN KEY (shipping_id) REFERENCES shippings(shipping_id)
)
All tables are empty for now. Here is query for creating shippings:
CREATE TABLE shippings (
shipping_id INT NOT NULL,
s_date DATE NOT NULL,
driver_id INT NOT NULL,
start_place VARCHAR(50) NOT NULL,
end_place VARCHAR(50) NOT NULL,
car_id INT NOT NULL,
price DECIMAL(5,2) NOT NULL,
PRIMARY KEY (shipping_id, s_date)
)
Here alters I've used after:
ALTER TABLE shippings ADD CONSTRAINT fk_car_id FOREIGN KEY (car_id) REFERENCES cars(car_id);
ALTER TABLE shippings ADD CONSTRAINT fk_driver_id FOREIGN KEY (driver_id) REFERENCES drivers(driver_id);
What's wrong in my queries? How to fix this and connect goods_and_shippings.s_date and shippings.s_date?
In general, foreign key references are to unique or primary keys. However, this condition is relaxed for INNODB, as explained in the documentation:
InnoDB permits a foreign key to reference any index column or group of
columns. However, in the referenced table, there must be an index
where the referenced columns are listed as the first columns in the
same order.
So, you can have a foreign reference to shipping_id because it is the first key in the primary key, but not to date. However, I would advise you to set up your foreign key relationships to complete primary keys. And, I usually have an auto-incrementing primary key in all tables, to facilitate such relationships.
I am curious to know what is best naming convention in terms of performance for mysql table names and column names. I am designing a new database for my project.
What I have used so far is use descriptive table/column names which sometimes seems long but I think it helps in easily understanding the use/function of a table.
For example see below DDL:
CREATE TABLE `product_configuration` (
`product_configuration_id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(20) NOT NULL,
`product_size_id` int(20) NOT NULL,
`product_color_id` int(20) NOT NULL,
`price` float NOT NULL,
`image` varchar(255) DEFAULT NULL,
`locked` tinyint(1) DEFAULT '0' COMMENT '1=locked, 0 =unlocked. if locked then this row can''t be deleted/updated',
`active` tinyint(1) DEFAULT '1' COMMENT '1=active, 0=inactive and wont display on frontend',
PRIMARY KEY (`product_configuration_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2342 DEFAULT CHARSET=latin1
And another DDL in which I use the primary key from above DDL as foreign key :
CREATE TABLE `product` (
`product_id` int(11) NOT NULL AUTO_INCREMENT,
`product_name` varchar(255) NOT NULL,
`product_description` varchar(255) NOT NULL,
`product_image` varchar(255) NOT NULL,
`price` float NOT NULL,
`active` tinyint(1) NOT NULL COMMENT '1=active, 0=inactive',
`date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`product_type_id` int(11) DEFAULT NULL,
`date_modified` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=latin1
Basically I use singular table names with table name as prefix in most of the column names inside that table and I keep the same name and datatype for primary and foreign keys so that I can easily know which foreign key relates to which primary key/tables.
But I wonder, do using long table/column names have performance impact when database size grows. Like instead of just using "id" as primary key I am using long "product_configuration_id".
Also if I name tables/columns in uppercase and lowercase mixed like
"ProductConfiguration"
for table name and
"ProductConfigurationId"
for column name will that have any performance impact or linux/windows environment compatibility issue.
Long table and column names do not have (any significant) performance impact. All tables and column references are turned into internal locators during the compilation phase of the query. So pretty much the only impact is having to query a longer query string. The parsing part of query compilation is usually ignored from a performance perspective.
The following is opinion-based. As a general rule, I follow these conventions for naming:
Table names are in the plural, because they contain multiple entities.
Each table (almost always) has an auto-incremented numeric primary key, which is the singular form of the table followed by Id.
This column is the first column defined, so I can use order by 1 desc to get the most recent rows added to the table.
The table name is not (generally) part of the column name. I always (try to) use table aliases, so including the table name would be redundant.
Foreign key references use the same column name as the primary key they are referring to, when possible, so I can use using for joins.
I admit that these are "opinion-based", so the real answer to your question is in the first paragraph.
I ran into troubles when I want to add new column mapped ONE TO ONE. It creates unique index on that column and while executing SQL it obviously fail, because that table already contains rows. It's not a problem to remove data in development database, but it will be in a production db.
This is how the SQL looks like:
$this->addSql('CREATE TABLE program_settings (id INT AUTO_INCREMENT NOT NULL, booking_cancel VARCHAR(155) NOT NULL, booking_ahead VARCHAR(155) NOT NULL, created_at DATETIME NOT NULL, modified_at DATETIME NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
$this->addSql('ALTER TABLE program ADD settings_id INT NOT NULL AFTER studio_id');
$this->addSql('ALTER TABLE program ADD CONSTRAINT FK_92ED778459949888 FOREIGN KEY (settings_id) REFERENCES program_settings (id)');
$this->addSql('CREATE UNIQUE INDEX UNIQ_92ED778459949888 ON program (settings_id)');
What should I do in that case?
I think the problem could be from your NOT NULL constraint on the settings_id column.
You have to:
Add you foreign key (settings_id) without the NOT NULL constraint
Update all your foreign fields (settings_id) with values
ALTER your foreign key (settings_id) with NOT NULL constraint
I am trying to write a PHP script to create 2 tables in the same database, which should be linked through a 1 (table category) to many (table page) relationship. Hence, primary key 'category_id' from the 'category' table should be the foreign key in the table 'page'.
The table 'category' creates successfully without problems:
$sql="CREATE TABLE category(
category_id SMALLINT NOT NULL AUTO_INCREMENT,
category VARCHAR(30) NOT NULL,
PRIMARY KEY (category_id),
UNIQUE (category)
)ENGINE=InnoDB DEFAULT CHARSET=utf8";
Then I am trying to create the second table 'page':
$sql="CREATE TABLE page(
page_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
category_id SMALLINT UNSIGNED NOT NULL,
title VARCHAR(100) NOT NULL,
description TINYTEXT NOT NULL,
content LONGTEXT NOT NULL,
date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (page_id),
FOREIGN KEY (category_id) REFERENCES category (category_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8";
And I get the following error:
Error creating table: Cannot add foreign key constraint
Could you please tell me what's wrong with my code? Thanks a lot in advance.
Per the MySql manual at http://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html:
Corresponding columns in the foreign key and the referenced key must have similar data types.
The size and sign of integer types must be the same.
The problem is that you're specifying your foreign key as UNSIGNED, while your primary is not. Make sure that your foreign key matches the specifications of its parent.
From the MySQL Using FOREIGN KEY Constraints documentation:
Corresponding columns in the foreign key and the referenced key must have similar data types. The size and sign of integer types must be the same.
In your page table, the category_id is SMALLINT UNSIGNED, but in category it's just SMALLINT. They need to be exactly the same.
The columns used for your foreign key must have a matching specification. Here you have one category_id column signed, while the other is unsigned. Change one.
you problem is the UNSIGNED in category_id.
try to remove it
try
$sql="CREATE TABLE page(
page_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
category_id SMALLINT NOT NULL,
title VARCHAR(100) NOT NULL,
description TINYTEXT NOT NULL,
content LONGTEXT NOT NULL,
date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (page_id),
FOREIGN KEY (page.category_id) REFERENCES category (category.category_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8";