Basically, I want to build the relation between the tables 'cities' and 'images'. They both have an ID column which is constrained by a third table called cities_images. Here's the structure of the table in the middle:
CREATE TABLE IF NOT EXISTS `cities_images` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`cityId` int(11) NOT NULL,
`imageId` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `imageId` (`imageId`),
KEY `cities_images_ibfk_2` (`cityId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
ALTER TABLE `cities_images`
ADD CONSTRAINT `cities_images_ibfk_2` FOREIGN KEY (`cityId`) REFERENCES `cities` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `cities_images_ibfk_1` FOREIGN KEY (`imageId`) REFERENCES `images` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
I have two models that work with the cities and images tables.
Relation inside Cities.php:
'citiesImages' => array(self::MANY_MANY, 'CitiesImages', 'cities_images(id,cityId)'),
Relation inside Images.php:
'citiesImages' => array(self::MANY_MANY, 'CitiesImages', 'cities_images(id,imageId)'),
I am trying a test action inside CitiesController with the following content:
$cities = Cities::model()->findByPk(2);
var_dump($cities->images);exit;
But this results in an error:
Property "Cities.images" is not defined.
Note that there is a city with ID=2 and there is a row in cities_images with cityId=2 and imageId=1. There is also a row in the images table with ID=1, so I don't see why I can't access the images associated with the given City.
You are just referencing the wrong name. Should be:
$cities = Cities::model()->findByPk(2);
var_dump($cities->citiesImages);exit;
Because that is how it is setup in the Cities.php model.
UPDATE:
Right, you need to simply change the models to point to the right model:
Cities.php:
'citiesImages' => array(self::MANY_MANY, 'Images', 'cities_images(imageId,cityId)'),
Images.php:
'citiesImages' => array(self::MANY_MANY, 'Cities', 'cities_images(cityId,imageId)'),
Related
I have this table which has a parent-child structure
CREATE TABLE `testable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
I now want to make sure every parent_id references a valid id.
Then I want to have an ON UPDATE CASCADE ON DELETE CASCADE on my id column so that if I change an id, every same parent_id gets updated automatically, and same for delete.
I've tried with the basic approach as follows:
ALTER TABLE `testable`
ADD CONSTRAINT `fk_testable_1`
FOREIGN KEY (`parent_id`)
REFERENCES `testable` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE;
I can then correctly try to update a row's parent_id with a non-existant id and the constraint blocks me.
The problem is then when I try to update an id which is referenced in some parent_id, there I get the following error:
ERROR 1451: 1451: Cannot delete or update a parent row: a foreign key constraint fails
The expected behaviour I want to achieve is my row id to change, and every row with that parent_id to update to reference the new id
Worth noting that parent_id is nullable and this is a table I use to create a dynamic side menu with sub-menus for my application.
I get error 1452 when updating a row in a parent table when running mariaDB 10.5.8. The tables are defined as follows:
> SHOW CREATE TABLE files;
files CREATE TABLE `files` (
`file_path` varchar(255) NOT NULL,
`md5` text NOT NULL,
`size` int(11) NOT NULL,
PRIMARY KEY (`file_path`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
> SHOW CREATE TABLE headlines;
headlines CREATE TABLE `headlines` (
`file_path` varchar(255) NOT NULL,
`headline_offset` int(11) NOT NULL,
-- other columns
PRIMARY KEY (`file_path`,`headline_offset`),
CONSTRAINT `headlines_ibfk_1` FOREIGN KEY (`file_path`) REFERENCES `files` (`file_path`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
> SHOW CREATE TABLE headline_closures;
headline_closures CREATE TABLE `headline_closures` (
`file_path` varchar(255) NOT NULL,
`headline_offset` int(11) NOT NULL,
`parent_offset` int(11) NOT NULL,
`depth` int(11) DEFAULT NULL,
PRIMARY KEY (`file_path`,`headline_offset`,`parent_offset`),
KEY `file_path` (`file_path`,`parent_offset`),
CONSTRAINT `headline_closures_ibfk_1` FOREIGN KEY (`file_path`, `headline_offset`) REFERENCES `headlines` (`file_path`, `headline_offset`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `headline_closures_ibfk_2` FOREIGN KEY (`file_path`, `parent_offset`) REFERENCES `headlines` (`file_path`, `headline_offset`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
The contents of the database (minimal example):
> SELECT * FROM files;
/path/to/foo1.org 106e9f12c9e4ff3333425115d148fbd4 6
> SELECT * FROM headlines;
/path/to/foo1.org 1 --other columns
> SELECT * FROM headline_closures;
/path/to/foo1.org 1 1 0
Executing the following produces the error (expected behavior is that the file path changes for all tables per the CASCADE clauses):
> UPDATE files SET file_path='/path/to/foo2.org' WHERE md5='106e9f12c9e4ff3333425115d148fbd4';
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`org_sql`.`headline_closures`, CONSTRAINT `headline_closures_ibfk_2` FOREIGN KEY (`file_path`, `parent_offset`) REFERENCES `headlines` (`file_path`, `headline_offset`))
Things I've tried (per MySQL cascade update failed when foreign key column referenced in composite primary key)
Removing the second ON DELETE CASCADE ON UPDATE CASCADE from the headline_closures table (same error)
Dropping the primary key from the headline_closures table and that produced error 150 (Foreign key constraint is incorrectly formed)
I thought (1) would work because the docs state to not have multiple CASCADEs that could change a single column; I'm not sure why (2) would work. What am I not getting here?
Also, if someone could explain why this same arrangement works for SQLite and postgreSQL that would be appreciated since I don't get the same error with those ;)
Edit 1
This same behavior happens with MySQL 8.0.22 (so not just a mariaDB error, not too surprising)
I don't get the error if I take away one of the foreign keys in headline_closures (so there is still one constraint that has ON UPDATE CASCADE)
If I remove the ON UPDATE CASCADE from headline_closures_ibfk_1 instead of headline_closures_ibfk_2, the error then complains about headline_closures_ibfk_1 (where it complained about headline_closures_ibfk_2 when I took the CASCADEs away from headline_closures_ibfk_2 or if I left them on both) so it seem that the error is due to updating the parent, having the cascade propagate to the headline_closures table where the second constraint doesn't see the update and therefore complains (or something)
Edit 2:
DELETE FROM files WHERE md5='106e9f12c9e4ff3333425115d148fbd4'; works as intended with the constraints as written above (no error and the the deletion propagates to all child tables).
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();
I have a child table. and foreign key there with ON DELETE CASCADE while creating the table.
There are no records either in child or parent table.
I want the primary key, foreign key to be as they are but want to remove only the CASCADING option from the child table .
is there anyway that i can Alter that child table.
Thank you.
The table:
SHOW CREATE TABLE table;
CREATE TABLE `table` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_departamento` int(11) unsigned DEFAULT NULL,
`name` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `id_departamento` (`id_departamento`),
CONSTRAINT `departamentos_direcciones_pedidos_ibfk_1` FOREIGN KEY (`id_departamento`) REFERENCES `departamentos` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
First drop foreign key.
ALTER TABLE departamentos_direcciones_pedidos DROP CONSTRAINT departamentos_direcciones_pedidos_ibfk_1;
Second, create the correct foreign key
ALTER TABLE departamentos_direcciones_pedidos ADD FOREIGN KEY (id_departamento) REFERENCES departamentos(id);
ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT }
The default is NO ACTION.
So try altering your child table back to default.
(Oracle) You can only alter the state of a constraint. ON DELETE is not a state. So you need to drop constraint and recreate it.
drop table t1 cascade constraints;
create table t1 (id number unique, rid number constraint t1_fk references t1(id) on delete cascade);
alter table t1 drop constraint t1_fk;
alter table t1 add constraint t1_fk foreign key(rid) references t1(id);
if you're using Oracle there are different dictionary views which might help you to recreate the constraint correctly
Export the database as a .sql file
Then press ctrl + H to replace all ON DELETE CASCADE with ""
Then drop the tables from the DB and use the new file to instantiate a new one without ON DELETE CASCADE
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`);