Cascade delete not working SQLite with 1:1 relationship - sqlite

I'm trying to set up a 1:1 relationship between two tables Places and People. A person has a home, and when that person is deleted the home should also be deleted. Other tables also use the Places table, so there is no column in the Places table that refers to the People table.
To try and achieve this, I've set the People table up so that when a row is deleted, there is a cascade delete on the foreign key pointing at the Places table row is also deleted.
CREATE TABLE IF NOT EXISTS "People" (
"Id" TEXT NOT NULL CONSTRAINT "PK_People" PRIMARY KEY,
"Name" TEXT NOT NULL,
"HomeId" TEXT NOT NULL,
CONSTRAINT "FK_People_Places_HomeId" FOREIGN KEY ("HomeId") REFERENCES "Places" ("Id") ON DELETE CASCADE
);
However, when I actually tried this, the row in the Places table still existed. Is there any way to fix this?
Fully runnable example
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS "Places" (
"Id" TEXT NOT NULL CONSTRAINT "PK_Places" PRIMARY KEY,
"Name" TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS "People" (
"Id" TEXT NOT NULL CONSTRAINT "PK_People" PRIMARY KEY,
"Name" TEXT NOT NULL,
"HomeId" TEXT NOT NULL,
CONSTRAINT "FK_People_Places_HomeId" FOREIGN KEY ("HomeId") REFERENCES "Places" ("Id") ON DELETE CASCADE
);
DELETE FROM Places;
DELETE FROM People;
INSERT INTO "Places" ("Id", "Name") VALUES ("6f81fa78-2820-48e1-a0a7-b0b71aa38262", "Castle");
INSERT INTO "People" ("Id", "HomeId", "Name") VALUES ("ccb079ce-b477-47cf-adba-9fdac6a41718", "6f81fa78-2820-48e1-a0a7-b0b71aa38262", "Fiona");
-- Should delete both the person and the place, but does not
DELETE FROM "People" WHERE "Id" = "ccb079ce-b477-47cf-adba-9fdac6a41718";
SELECT pl.Name "Place Name",
po.Name "Person Name"
FROM Places pl
LEFT JOIN People po USING(Name)
UNION ALL
SELECT pl.Name,
po.Name
FROM People po
LEFT JOIN Places pl USING(Name)
WHERE pl.Name IS NULL;

The "ON DELETE CASCADE" action for the foreign key that you defined in the table People for the column HomeId which references the column Id of the table Places means that:
whenever you delete a row in the table Places (which is the parent
table in this relationship) all rows in the table People that hold a
reference to the deleted row will also be deleted.
See the demo.
In your case you are deleting a row in the table People and this does not affect at all the table Places.

Related

Whats the proper way to structure a SQLite DB with items and lists of items to create them [duplicate]

Can anyone explain how to implement one-to-one, one-to-many and many-to-many relationships while designing tables with some examples?
One-to-one: Use a foreign key to the referenced table:
student: student_id, first_name, last_name, address_id
address: address_id, address, city, zipcode, student_id # you can have a
# "link back" if you need
You must also put a unique constraint on the foreign key column (addess.student_id) to prevent multiple rows in the child table (address) from relating to the same row in the referenced table (student).
One-to-many: Use a foreign key on the many side of the relationship linking back to the "one" side:
teachers: teacher_id, first_name, last_name # the "one" side
classes: class_id, class_name, teacher_id # the "many" side
Many-to-many: Use a junction table (example):
student: student_id, first_name, last_name
classes: class_id, name, teacher_id
student_classes: class_id, student_id # the junction table
Example queries:
-- Getting all students for a class:
SELECT s.student_id, last_name
FROM student_classes sc
INNER JOIN students s ON s.student_id = sc.student_id
WHERE sc.class_id = X
-- Getting all classes for a student:
SELECT c.class_id, name
FROM student_classes sc
INNER JOIN classes c ON c.class_id = sc.class_id
WHERE sc.student_id = Y
Here are some real-world examples of the types of relationships:
One-to-one (1:1)
A relationship is one-to-one if and only if one record from table A is related to a maximum of one record in table B.
To establish a one-to-one relationship, the primary key of table B (with no orphan record) must be the secondary key of table A (with orphan records).
For example:
CREATE TABLE Gov(
GID number(6) PRIMARY KEY,
Name varchar2(25),
Address varchar2(30),
TermBegin date,
TermEnd date
);
CREATE TABLE State(
SID number(3) PRIMARY KEY,
StateName varchar2(15),
Population number(10),
SGID Number(4) REFERENCES Gov(GID),
CONSTRAINT GOV_SDID UNIQUE (SGID)
);
INSERT INTO gov(GID, Name, Address, TermBegin)
values(110, 'Bob', '123 Any St', '1-Jan-2009');
INSERT INTO STATE values(111, 'Virginia', 2000000, 110);
One-to-many (1:M)
A relationship is one-to-many if and only if one record from table A is
related to one or more records in table B. However, one record in table B cannot be related to more than one record in table A.
To establish a one-to-many relationship, the primary key of table A (the "one" table) must be the secondary key of table B (the "many" table).
For example:
CREATE TABLE Vendor(
VendorNumber number(4) PRIMARY KEY,
Name varchar2(20),
Address varchar2(20),
City varchar2(15),
Street varchar2(2),
ZipCode varchar2(10),
Contact varchar2(16),
PhoneNumber varchar2(12),
Status varchar2(8),
StampDate date
);
CREATE TABLE Inventory(
Item varchar2(6) PRIMARY KEY,
Description varchar2(30),
CurrentQuantity number(4) NOT NULL,
VendorNumber number(2) REFERENCES Vendor(VendorNumber),
ReorderQuantity number(3) NOT NULL
);
Many-to-many (M:M)
A relationship is many-to-many if and only if one record from table A is related to one or more records in table B and vice-versa.
To establish a many-to-many relationship, create a third table called "ClassStudentRelation" which will have the primary keys of both table A and table B.
CREATE TABLE Class(
ClassID varchar2(10) PRIMARY KEY,
Title varchar2(30),
Instructor varchar2(30),
Day varchar2(15),
Time varchar2(10)
);
CREATE TABLE Student(
StudentID varchar2(15) PRIMARY KEY,
Name varchar2(35),
Major varchar2(35),
ClassYear varchar2(10),
Status varchar2(10)
);
CREATE TABLE ClassStudentRelation(
StudentID varchar2(15) NOT NULL,
ClassID varchar2(14) NOT NULL,
FOREIGN KEY (StudentID) REFERENCES Student(StudentID),
FOREIGN KEY (ClassID) REFERENCES Class(ClassID),
UNIQUE (StudentID, ClassID)
);
One-to-many
The one-to-many table relationship looks as follows:
In a relational database system, a one-to-many table relationship links two tables based on a Foreign Key column in the child which references the Primary Key of the parent table row.
In the table diagram above, the post_id column in the post_comment table has a Foreign Key relationship with the post table id Primary Key column:
ALTER TABLE
post_comment
ADD CONSTRAINT
fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
One-to-one
The one-to-one table relationship looks as follows:
In a relational database system, a one-to-one table relationship links two tables based on a Primary Key column in the child which is also a Foreign Key referencing the Primary Key of the parent table row.
Therefore, we can say that the child table shares the Primary Key with the parent table.
In the table diagram above, the id column in the post_details table has also a Foreign Key relationship with the post table id Primary Key column:
ALTER TABLE
post_details
ADD CONSTRAINT
fk_post_details_id
FOREIGN KEY (id) REFERENCES post
Many-to-many
The many-to-many table relationship looks as follows:
In a relational database system, a many-to-many table relationship links two parent tables via a child table which contains two Foreign Key columns referencing the Primary Key columns of the two parent tables.
In the table diagram above, the post_id column in the post_tag table has also a Foreign Key relationship with the post table id Primary Key column:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post
And, the tag_id column in the post_tag table has a Foreign Key relationship with the tag table id Primary Key column:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag
One to one (1-1) relationship:
This is relationship between primary & foreign key (primary key relating to foreign key only one record). this is one to one relationship.
One to Many (1-M) relationship:
This is also relationship between primary & foreign keys relationships but here primary key relating to multiple records (i.e. Table A have book info and Table B have multiple publishers of one book).
Many to Many (M-M): Many to many includes two dimensions, explained fully as below with sample.
-- This table will hold our phone calls.
CREATE TABLE dbo.PhoneCalls
(
ID INT IDENTITY(1, 1) NOT NULL,
CallTime DATETIME NOT NULL DEFAULT GETDATE(),
CallerPhoneNumber CHAR(10) NOT NULL
)
-- This table will hold our "tickets" (or cases).
CREATE TABLE dbo.Tickets
(
ID INT IDENTITY(1, 1) NOT NULL,
CreatedTime DATETIME NOT NULL DEFAULT GETDATE(),
Subject VARCHAR(250) NOT NULL,
Notes VARCHAR(8000) NOT NULL,
Completed BIT NOT NULL DEFAULT 0
)
-- This table will link a phone call with a ticket.
CREATE TABLE dbo.PhoneCalls_Tickets
(
PhoneCallID INT NOT NULL,
TicketID INT NOT NULL
)

Can you use Nulls as part of a multi-column uniqueness check in SQLite?

Consider a simple self-referencing table in SQLite with the following fields
Create Table Test{
Id INTEGER PRIMARY KEY, <-- Alias for the RowId
Name TEXT NOT NULL CHECK(length(Name) > 0),
ParentId INTEGER REFERENCES Test(Id),
};
CREATE UNIQUE INDEX IX_UniqueNamePerLevel ON Test(ParentId, Name);
We're trying to set a uniqueness constraint on Name for all items which share the same ParentId. In other words, you can have two items with the name 'Joe' provided those items do not have the same ParentId.
The problem is that SQLite seems to treat nulls as distinct, meaning for any level except root items, the constraint works, but you can have fifteen 'Joe' entries all with a ParentId of 'null.'
Bonus points if you can show how to make that constraint trim leading and trailing whitespace on insert/update, and ignore case for the uniqueness constraint too.
SQLite treats NULLs in UNIQUE constraints as distinct for compatibility with other databases.
It is not possible to use a CHECK constraint for this because it would have to access other rows from the table, but subqueries are not allowed in CHECK.
You would have to use a trigger:
CREATE TRIGGER Test_ParentName_unique_insert_check
AFTER INSERT ON Test
FOR EACH ROW
WHEN NEW.ParentId IS NULL
BEGIN
SELECT RAISE(ABORT, 'root items must be unique, too')
FROM Test
WHERE ParentId IS NULL
AND Name = NEW.Name
AND Id <> NEW.Id;
END;

How to write a delete trigger in Oracle PL/SQL - stuck on identifying "matching rows"

I have a trigger I'm writing whereby , once I delete a row, I want to delete the corresponding row in the another table (which is common_cis.security_function ).
and the source table is party.security_function
Here are the columns in common_cis.security_function :
URL
SCRTY_FUNC_NAME
SCRTY_FUNC_DESC
IDN
CREATE_TMSTMP
CNCRCY_USER_IDN
Here are the columns in party.security_function :
UPDATE_USER_SRC_SYS_CD
UPDATE_USER_ID
UPDATE_TS
SCRT_FUNC_NM
SCRT_FUNC_DESC
CREAT_USER_SRC_SYS_CD
CREAT_USER_ID
CREAT_TS
What I have so far is :
delete from common_cis.security_function CCSF
where CCSF.SCRTY_FUNC_NAME = :new.SCRT_FUNC_NM;
Is this the right idea? Or do I use some kind of row-ID ?
thanks
I think you should use integrity constraints for that, namely foreign key constraint with "ON DELETE CASCADE" condition.
Here is an example, but check first is there tables in your schema with names that I used:
-- create tables:
create table master_table(
URL varchar2(1000),
SCRTY_FUNC_NAME varchar2(100),
SCRTY_FUNC_DESC varchar2(1000));
create table detail_table(
SCRT_FUNC_NM varchar2(100),
SCRT_FUNC_DESC varchar2(1000),
UPDATE_USER_ID number,
UPDATE_TS varchar2(100));
-- add primary key and foreign key constraints:
alter table master_table add constraint function_pk primary key (SCRTY_FUNC_NAME);
alter table detail_table add constraint function_fk foreign key (SCRT_FUNC_NM) references master_table (SCRTY_FUNC_NAME) on delete cascade;
-- fill tables with data:
insert into master_table
values ('url number 1', 'sec function #1', 'description of function #1');
insert into detail_table
values('sec function #1', 'description', 1, '123abc');
insert into detail_table
values('sec function #1', 'description', 2, '456xyz');
-- check tables: first contains 1 row and second - 2 rows
select count(*) from master_table;
select count(*) from detail_table;
-- delete rows from first table only:
delete from master_table;
-- check tables once again - both are empty:
select count(*) from master_table;
select count(*) from detail_table;
-- clear test tables:
drop table detail_table;
drop table master_table;

INSERT OR IGNORE INTO doesn't work

I have a table created as:
create table association (_id integer unique primary key autoincrement , id_rules integer, id_places integer)";
To avoid replication of entry, I use the statement INSERT OR IGNOR, but it doesn't work. For example,
value (id_rules , id_places) = ("11","1") alredy in table, but using:
INSERT OR IGNORE INTO association (id_rules , id_places) VALUES ("11","1")
a new row is created.
Please, do anyone Know hwere is my mistake?
INSERT OR IGNORE will ignore any rows that would violate a UNIQUE constraint.
The only such constraint is on the _id column, which you did not specify.
If you want to prevent duplicates in those two columns, you have to add a constraint for them to the table definition:
CREATE TABLE association (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
id_rules INTEGER,
id_places INTEGER,
UNIQUE (id_rules, id_places)
);

Oracle: searching over a range of values?

CREATE TABLE "DEPARTMENT"
( "DEP_NO" NUMBER(*,0) NOT NULL ENABLE,
"SSN" NUMBER(*,0),
"STREET" CHAR(40) NOT NULL ENABLE,
"CITY" CHAR(25) NOT NULL ENABLE,
"NAME" CHAR(50) NOT NULL ENABLE,
"BUDGET" NUMBER(8,2),
CONSTRAINT "PK_DEPARTMENT" PRIMARY KEY ("DEP_NO") ENABLE
) ;
ALTER TABLE "DEPARTMENT" ADD CONSTRAINT "FK_DEPARTMENT_EMPLOYEE" FOREIGN KEY ("SSN")
REFERENCES "EMPLOYEE" ("SSN") ENABLE;
ALTER TABLE "DEPARTMENT" ADD CONSTRAINT "FK_DEPARTMENT_LOCATION" FOREIGN KEY ("STREET", "CITY")
REFERENCES "LOCATION" ("STREET", "CITY") ENABLE;
what is the correct way in building a data base , is it better to create the tables with their primary keys , insert the data and then link these tables to another tables with the foreign key or it is better to create all the tables , link them together and then insert the required data ???
There is no correct way. Both approaches can be used.
The simpler approach is to first create all the tables, indexes and constraints and then to insert the data.
For maximum performance, first create just the tables and the primary key indexes, then insert the data and finally create the additional indexes and the constraints.

Resources