MySQL and foreign key conflicts when trying to INSERT - sql

I'm doing the Agile Yii book.
Anyway, I'm trying to execute this command:
INSERT INTO tbl_project_user_assignment (project_id, user_id) values ('1','1'), ('1','2');
And I get this error:
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`trackstar_dev`.`tbl_project_user_assignment`, CONSTRAINT `FK_project_user` FOREIGN KEY (`project_id`) REFERENCES `tbl_project` (`id`) ON DELETE CASCADE)
So.. I figure let's see if tbl_project table have project_id=1. Did a quick SELECT * FROM tbl_project; and the project exist.
Ok then let's just check the user, SELECT * FROM tbl_user; Yup 2 user with id 1 and 2.
What am I doing wrong? Is there a typo? The agile yii book have several typos but they're not as serious and it's too new so there's no errata reported (checked already).
Here's the database schema from the source code:
-- Disable foreign keys
SET FOREIGN_KEY_CHECKS = 0 ;
-- Create tables section -------------------------------------------------
-- Table tbl_project
CREATE TABLE IF NOT EXISTS `tbl_project` (
`id` INTEGER NOT NULL auto_increment,
`name` varchar(128) NOT NULL,
`description` text NOT NULL,
`create_time` DATETIME default NULL,
`create_user_id` INTEGER default NULL,
`update_time` DATETIME default NULL,
`update_user_id` INTEGER default NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
;
-- DROP TABLE IF EXISTS `tbl_issue` ;
CREATE TABLE IF NOT EXISTS `tbl_issue`
(
`id` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` varchar(256) NOT NULL,
`description` varchar(2000),
`project_id` INTEGER,
`type_id` INTEGER,
`status_id` INTEGER,
`owner_id` INTEGER,
`requester_id` INTEGER,
`create_time` DATETIME,
`create_user_id` INTEGER,
`update_time` DATETIME,
`update_user_id` INTEGER
) ENGINE = InnoDB
;
-- DROP TABLE IF EXISTS `tbl_user` ;
-- Table User
CREATE TABLE IF NOT EXISTS `tbl_user`
(
`id` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
`email` Varchar(256) NOT NULL,
`username` Varchar(256),
`password` Varchar(256),
`last_login_time` Datetime,
`create_time` DATETIME,
`create_user_id` INTEGER,
`update_time` DATETIME,
`update_user_id` INTEGER
) ENGINE = InnoDB
;
-- DROP TABLE IF EXISTS `tbl_project_user_assignment` ;
-- Table User
CREATE TABLE IF NOT EXISTS `tbl_project_user_assignment`
(
`project_id` Int(11) NOT NULL,
`user_id` Int(11) NOT NULL,
`create_time` DATETIME,
`create_user_id` INTEGER,
`update_time` DATETIME,
`update_user_id` INTEGER,
PRIMARY KEY (`project_id`,`user_id`)
) ENGINE = InnoDB
;
-- The Relationships
ALTER TABLE `tbl_issue` ADD CONSTRAINT `FK_issue_project` FOREIGN KEY (`project_id`) REFERENCES `tbl_project` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
ALTER TABLE `tbl_issue` ADD CONSTRAINT `FK_issue_owner` FOREIGN KEY (`owner_id`) REFERENCES `tbl_user` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
ALTER TABLE `tbl_issue` ADD CONSTRAINT `FK_issue_requester` FOREIGN KEY (`requester_id`) REFERENCES `tbl_user` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
ALTER TABLE `tbl_project_user_assignment` ADD CONSTRAINT `FK_project_user` FOREIGN KEY (`project_id`) REFERENCES `tbl_project` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
ALTER TABLE `tbl_project_user_assignment` ADD CONSTRAINT `FK_user_project` FOREIGN KEY (`user_id`) REFERENCES `tbl_user` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
-- Insert some seed data so we can just begin using the database
INSERT INTO `tbl_user`
(`email`, `username`, `password`)
VALUES
('test1#notanaddress.com','Test_User_One', MD5('test1')),
('test2#notanaddress.com','Test_User_Two', MD5('test2'))
;
-- Enable foreign keys
SET FOREIGN_KEY_CHECKS = 1 ;
Anyway, thanks in advance!
EDIT:
Clarification that the project does indeed exist ^^.
mysql> select id,name from tbl_project;
+----+-------------------+
| id | name |
+----+-------------------+
| 6 | Project 1 |
| 1 | project zombied 1 |
+----+-------------------+
2 rows in set (0.00 sec)

The project_id and user_id in tbl_project_user_assignment are typed as INT(11) rather than INTEGER. I'm inclined to think that INTEGER is 4 BYTES and INT(11) would go to 8 BYTES.
As commented above INTEGER fixes the problem.

This is a strange issue you have encountered, as well as an odd fix for it. As far as I am aware, there is no internal difference between INTEGER, INT, OR INT(XX) (where XX is some number) They are all the same datatype with the same byte storage allocation and min/max range. This should not play a role in MySQL evaluation of type mismatch for some fk relationships. My version/configuration of MySQL (5.1.49) does not throw the same constraint violation you are experiencing when given using INT(11) in one table and INTEGER in another. I wonder if this is somehow more related to your configuration or if you are using other external DB tools.
One can read more about the internals of MySQL datatype here:
http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html
of particular interest on this page:
Another extension is supported by
MySQL for optionally specifying the
display width of integer data types in
parentheses following the base keyword
for the type (for example, INT(4)).
This optional display width may be
used by applications to display
integer values having a width less
than the width specified for the
column by left-padding them with
spaces. (That is, this width is
present in the metadata returned with
result sets. Whether it is used or not
is up to the application.) The display
width does not constrain the range of
values that can be stored in the
column, nor the number of digits that
are displayed for values having a
width exceeding that specified for the
column. For example, a column
specified as SMALLINT(3) has the usual
SMALLINT range of -32768 to 32767, and
values outside the range permitted by
three characters are displayed using
more than three characters.

Related

PostgreSQL CHECK Constraint on columns other than foreign keys

I have a situation where I want to create a table that associates records from other tables by the id. A constraint of the association is that the year must be the same in the record being associated in each table... Is there a way to get PostgreSQL to CHECK this condition on INSERT?
Table 1:
CREATE TABLE "tenant"."report" (
"id" UUID NOT NULL DEFAULT "pascal".uuid_generate_v1(),
CONSTRAINT "report_pkc_id" PRIMARY KEY ("id"),
"reporting_period" integer NOT NULL,
"name" VARCHAR(64) NOT NULL,
CONSTRAINT "report_uc__name" UNIQUE ("reporting_period", "name"),
"description" VARCHAR(2048) NOT NULL
);
Table 2:
CREATE TABLE "tenant"."upload_file" (
"id" UUID NOT NULL DEFAULT "pascal".uuid_generate_v1(),
CONSTRAINT "upload_file_pkc_id" PRIMARY KEY ("id"),
"file_name" VARCHAR(256) NOT NULL,
"reporting_period" integer
)
Association Table:
CREATE TABLE "tenant"."report_upload_files"
(
"report_id" UUID NOT NULL,
CONSTRAINT "report_upload_files_pkc_tenant_id" PRIMARY KEY ("report_id"),
CONSTRAINT "report_upload_files_fkc_tenant_id" FOREIGN KEY ("report_id")
REFERENCES "tenant"."report" ("id") MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
"upload_file_id" UUID NOT NULL,
CONSTRAINT "report_upload_files_fkc_layout_id" FOREIGN KEY ("upload_file_id")
REFERENCES "tenant"."upload_file" ("id") MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)
I want to add something like to the association table CREATE statement:
CHECK ("tenant"."report"."reporting_period" = "tenant"."upload_file"."reporting_period")
You're solving problems that you've created yourself.
Your data model is a typical one-to-many relationship. You don't need an association table. Also, you don't need the same column in two related tables, one of them is redundant. Use the model as shown below to avoid typical problems resulting from lack of normalization.
create table tenant.report (
id uuid primary key default pascal.uuid_generate_v1(),
reporting_period integer not null,
name varchar(64) not null,
description varchar(2048) not null,
unique (reporting_period, name)
);
create table tenant.upload_file (
id uuid primary key default pascal.uuid_generate_v1(),
report_id uuid references tenant.report(id),
file_name varchar(256) not null
);
Using this approach there's no need to ensure that the reporting periods match between the associated records.
BTW, I would use text instead of varchar(n) and integer (serial) instead of uuid.
Using a TRIGGER function I was able to achieve the desired effect:
CREATE FUNCTION "tenant".report_upload_files_create() RETURNS TRIGGER AS
$report_upload_files_create$
BEGIN
IF NOT EXISTS (
SELECT
*
FROM
"tenant"."report",
"tenant"."upload_file"
WHERE
"tenant"."report"."id" = NEW."report_id"
AND
"tenant"."upload_file"."id" = NEW."upload_file_id"
AND
"tenant"."report"."reporting_period" = "tenant"."upload_file"."reporting_period"
)
THEN
RAISE EXCEPTION 'Report and Upload File reporting periods do not match';
END IF;
RETURN NEW;
END
$report_upload_files_create$ LANGUAGE plpgsql;
CREATE TRIGGER "report_upload_files_create" BEFORE INSERT ON "tenant"."report_upload_files"
FOR EACH ROW EXECUTE PROCEDURE "tenant".report_upload_files_create();

Reorder rows in database

I need to change order of rows in database table.
My table has 4 columns and 7 rows. I need to reorder these rows
pk_i_id int(10) unsigned Auto Increment
s_name varchar(255) NULL
s_heading varchar(255) NULL
s_order_type varchar(10) NULL
In Adminer, when I've changed pk_i_id value(number) something else, I'm getting this error...
Cannot delete or update a parent row: a foreign key constraint fails (`database_name`.`oc_t_item_custom_attr_categories`, CONSTRAINT `oc_t_item_custom_attr_categories_ibfk_1` FOREIGN KEY (`fk_i_group_id`) REFERENCES `oc_t_item_custom_attr_groups` (`pk_i_id`))
Do you know how to change it ? Thank you
Edit
oc_t_item_custom_attr_categories
fk_i_group_id int(10) unsigned
fk_i_category_id int(10) unsigned
indexes
PRIMARY fk_i_group_id, fk_i_category_id
INDEX fk_i_category_id
foregin keys
fk_i_group_id oc_t_item_custom_attr_groups_2(pk_i_id) RESTRICT RESTRICT
fk_i_category_id oc_t_category(pk_i_id) RESTRICT RESTRICT
You need to change your foreign key on table database_name.oc_t_item_custom_attr_categories so that it updates along with column it references.
ALTER TABLE database_name.oc_t_item_custom_attr_categories DROP CONSTRAINT oc_t_item_custom_attr_categories_ibfk_1;
ALTER TABLE database_name.oc_t_item_custom_attr_categories
ADD CONSTRAINT oc_t_item_custom_attr_categories_ibfk_1 FOREIGN KEY (fk_i_group_id)
REFERENCES oc_t_item_custom_attr_groups (pk_i_id)
ON UPDATE CASCADE;
Since MariaDB seem to not support ADDING foreign keys after table creation, this is how it should work for you, assuming description of tables is correct:
RENAME TABLE oc_t_item_custom_attr_categories TO oc_t_item_custom_attr_categories_2;
CREATE TABLE oc_t_item_custom_attr_categories (
fk_i_group_id int(10) unsigned,
fk_i_category_id int(10) unsigned,
PRIMARY KEY(fk_i_group_id, fk_i_category_id),
INDEX (fk_i_category_id),
CONSTRAINT `oc_t_item_custom_attr_categories_ibfk_1` FOREIGN KEY (fk_i_group_id)
REFERENCES oc_t_item_custom_attr_groups (pk_i_id)
ON UPDATE CASCADE,
CONSTRAINT `oc_t_item_custom_attr_categories_ibfk_2` FOREIGN KEY (fk_i_category_id)
REFERENCES oc_t_category (pk_i_id)
) ENGINE = XtraDB; --change engine to what you are using
INSERT INTO oc_t_item_custom_attr_categories SELECT * FROM oc_t_item_custom_attr_categories_2;
How it works on example data in MySQL database: http://rextester.com/ZAKR50399

Creating relationship between primary key to composite key -- phpMyAdmin

I am trying to create a relation between a field 'fldEmpID' in my Employees table to a foreign composite key which consists of fldEmpID and fldEventID but it is not allowing the relation to be created. I don't understand why this relation won't work, I was able to create a similar relation between fldEventID from an Events to the composite key. Both fldEmpID fields in each table are int(11). What can I do to create this relation?
The following are the two tables... (I would like to keep the composite key on the table to the right as it helps to prevent duplicates and works well)
It seems to work as expected for me. I created the tables and used the Designer tab to create the relation (by selecting the "Create relation" icon, then clicking fldEmpId in table a, and finally selecting fldEmpID in table b).
For reference, I pasted below the structure of my table (which includes the keys and restraints)
CREATE TABLE IF NOT EXISTS `a` (
`fldEmpId` int(11) NOT NULL,
`fldEmpName` varchar(50) NOT NULL,
`fldEmail` varchar(50) NOT NULL,
`fldPassHash` varchar(50) NOT NULL,
`fldPassSalt` varchar(50) NOT NULL,
`fldAdmin` enum('1','2') NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `b` (
`fldEmpID` int(11) NOT NULL,
`fldEventID` bigint(20) unsigned NOT NULL,
`fldDTAdded` datetime NOT NULL,
`fldDTRemoved` datetime NOT NULL,
`fldPosition` enum('0','1','2','3','4','5') NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `a`
ADD PRIMARY KEY (`fldEmpId`);
ALTER TABLE `b`
ADD PRIMARY KEY (`fldEmpID`), ADD UNIQUE KEY `fldEventID` (`fldEventID`);
ALTER TABLE `a`
MODIFY `fldEmpId` int(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE `b`
ADD CONSTRAINT `fk` FOREIGN KEY (`fldEmpID`) REFERENCES `a` (`fldEmpId`);

I am not able to create foreign key in mysql Error 150. Please help

i am trying to create a foreign key in my table. But when i executes my query it shows me error 150.
Error Code : 1025
Error on create foreign key of '.\vts\#sql-6ec_1' to '.\vts\tblguardian' (errno: 150)
(0 ms taken)
My Queries are
Query to create a foreign Key
alter table `vts`.`tblguardian` add constraint `FK_tblguardian` FOREIGN KEY (`GuardianPickPointId`) REFERENCES `tblpickpoint` (`PickPointId`)
Primary Key table
CREATE TABLE `tblpickpoint` (
`PickPointId` int(4) NOT NULL auto_increment,
`PickPointName` varchar(500) default NULL,
`PickPointLabel` varchar(500) default NULL,
`PickPointLatLong` varchar(100) NOT NULL,
PRIMARY KEY (`PickPointId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC
Foreign Key Table
CREATE TABLE `tblguardian` (
`GuardianId` int(4) NOT NULL auto_increment,
`GuardianName` varchar(500) default NULL,
`GuardianAddress` varchar(500) default NULL,
`GuardianMobilePrimary` varchar(15) NOT NULL,
`GuardianMobileSecondary` varchar(15) default NULL,
`GuardianPickPointId` int(4) default NULL,
PRIMARY KEY (`GuardianId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Your problem is the type of the columns in your constraint are different. They must be the same.
`PickPointId` int(4) NOT NULL auto_increment,
`GuardianPickPointId` varchar(100) default NULL,
For more information see the documentation:
Corresponding columns in the foreign key and the referenced key must have similar internal data types inside InnoDB so that they can be compared without a type conversion. The size and sign of integer types must be the same. The length of string types need not be the same. For nonbinary (character) string columns, the character set and collation must be the same.
Have a look at this step by step issue list
MySQL Error Number 1005 Can’t create table ‘.\mydb#sql-328_45.frm’ (errno: 150)

Two n x m relationships with the same table in mysql

I want to create a database in which there's an n x m relationship between the table drug and the table article and an n x m relationship between the table target and the table article.
I get the error: Cannot delete or update a parent row: a foreign key constraint fails
What do I have to change in my code?
DROP TABLE IF EXISTS `textmine`.`article`;
CREATE TABLE `textmine`.`article` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Pubmed ID',
`abstract` blob NOT NULL,
`authors` blob NOT NULL,
`journal` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `textmine`.`drugs`;
CREATE TABLE `textmine`.`drugs` (
`id` int(10) unsigned NOT NULL COMMENT 'This ID is taken from the biosemantics dictionary',
`primaryName` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `textmine`.`targets`;
CREATE TABLE `textmine`.`targets` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`primaryName` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `textmine`.`containstarget`;
CREATE TABLE `textmine`.`containstarget` (
`targetid` int(10) unsigned NOT NULL,
`articleid` int(10) unsigned NOT NULL,
KEY `target` (`targetid`),
KEY `article` (`articleid`),
CONSTRAINT `article` FOREIGN KEY (`articleid`) REFERENCES `article` (`id`),
CONSTRAINT `target` FOREIGN KEY (`targetid`) REFERENCES `targets` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `textmine`.`contiansdrug`;
CREATE TABLE `textmine`.`contiansdrug` (
`drugid` int(10) unsigned NOT NULL,
`articleid` int(10) unsigned NOT NULL,
KEY `drug` (`drugid`),
KEY `article` (`articleid`),
CONSTRAINT `article` FOREIGN KEY (`articleid`) REFERENCES `article` (`id`),
CONSTRAINT `drug` FOREIGN KEY (`drugid`) REFERENCES `drugs` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
You are trying to create tables out of order.
For example you are trying to create contiansdrug table which refers to table drugs before drugs table.
Remember that any SQL, even DDL, tries to leave database in consistent state.
I would recommend putting the commands in proper order. Alternatively you have options to turn off the checks temporarily and run the creation scrip inside transaction, see the instructions here
Relevant section is
SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS=0;
.. your script..
SET FOREIGN_KEY_CHECKS = 1;
COMMIT;
SET AUTOCOMMIT = 1;
EDIT:
OK, try not to have same names for constraints. Reading the fine manual enlightens:
If the CONSTRAINT symbol clause is
given, the symbol value must be unique
in the database. If the clause is not
given, InnoDB creates the name
automatically.
EDIT2:
To spell it out, you have duplicate constrain symbol article, rename it and all will be fine.
Standard practice is if you name your constrains to use names that describe what is related, for example containsdrug_acticelid_article_id (firsttablename_column_secondtablename_column) would be unique and descriptive.
I solved the problem by not declaring the Foreign Key inside of MySql but simply declaring them as ints.