How to disable delete on table for certain id in h2? - sql

Lets suppose we have student table in h2 and every student has id (primary key). Is it possible to implement trigger (or another mechanism) to disable delete operation if id == 100. I want to have such protection on DB level, but not on application level.

One solution is obviously a trigger that prevents deleting or changing the value.
Another method is to use a foreign key constraint. Create a table of ids that you want to keep and use a foreign key reference:
create table keep_these_students (
student_id int,
constraint fk_keep_these_students_student_id foreign key (student_id) references students(id)
);
insert into keep_these_students (student_id)
values (100);
The foreign key definition will require that the row cannot be deleted if the id changes. And, it is easy to add additional ids -- without changing triggers.

Related

Foreign key to table A or table B

Consider a situation where I define an object, a group of objects, then a table that links them together:
CREATE TABLE obj (
id INTEGER PRIMARY KEY,
name text
) ;
CREATE TABLE group (
id INTEGER PRIMARY KEY ;
grpname TEXT
) ;
CREATE TABLE relation (
objid INTEGER,
grpid INTEGER,
PRIMARY KEY (objid, grpid)
) ;
I am looking for cascade delete when applicable so I add the foreign key
ALTER TABLE relation
ADD FOREIGN KEY (objid)
REFERENCES obj(id)
ON DELETE CASCADE ;
ALTER TABLE relation
ADD FOREIGN KEY (grpid)
REFERENCES group(id)
ON DELETE CASCADE ;
So far is all OK. Now suppose I want to add support for group of groups. I am thinking to change the relation table like this:
CREATE TABLE relation_ver1 (
parent INTEGER,
child INTEGER,
PRIMARY KEY (parent, child)
) ;
ALTER TABLE relation_ver1
ADD FOREIGN KEY (parent)
REFERENCES group(id)
ON DELETE CASCADE ;
Here I get to the question: I would like to apply cascade delete to child too, but I do not know here if child refers to a group or object.
Can I add a foreign key to table obj or group?
The only solution I have found do fare is add child_obj and child_grp fields, add the relative foreign keys and then, when inserting e.g an object use a 'special' (sort of null) group, and do the reverse when inserting subgroup.
Consider the relation:
relation_ver1(parent, child_obj, child_group)
I claim that this relation has the following disadvantages:
You have to deal with the NULL special case.
Approx. 1/3 of values are NULL. NULL values are bad.
Fortunately, there is an easy way to fix this. Since there is a multi-value dependency in your data, you can decompose your table into 2 smaller tables that are 4NF compliant. For example:
relation_ver_obj(parent, child_obj) and
relation_ver_grp(parent, child_group).
The primary reason why we have foreign keys is not so as to be able to do things like cascaded deletes. The primary reason for the existence of foreign keys is referential integrity.
This means that grpid is declared as REFERENCES group(id) in order to ensure that grpid will never be allowed to take any value which is not found in group(id). So, it is an issue of validity. A cascaded DELETE also boils down to validity: if a key is deleted, then any and all foreign keys referring to that key would be left invalid, so clearly, something must be done about them. Cascaded deletion is one possible solution. Setting the foreign key to NULL, thus voiding the relationship, is another possible solution.
Your notion of having a child id refer to either a group or an object violates any notion of referential integrity. Relational Database theory has no use and no provision for polymorphism. A key must refer to one and only one kind of entity. If not, then you start running into problems like the one you have just discovered, but even worse, you cannot have any referential integrity guarantees in your database. That's not a nice situation to be in.
The way to handle the need of relationships to different kinds of entities is with the use of a set of foreign keys, one for each possible related entity, out of which only one may be non-NULL. So, here is how it would look like:
CREATE TABLE tree_relation (
parent_id INTEGER,
child_object_id INTEGER,
child_group_id INTEGER,
PRIMARY KEY (parent_id, child_object_id, child_group_id) );
ALTER TABLE tree_relation
ADD FOREIGN KEY (parent_id) REFERENCES group(id) ON DELETE CASCADE;
ALTER TABLE tree_relation
ADD FOREIGN KEY (child_object_id) REFERENCES object(id) ON DELETE CASCADE;
ALTER TABLE tree_relation
ADD FOREIGN KEY (child_group_id) REFERENCES group(id) ON DELETE CASCADE;
All you need to do is ensure that only one of child_object_id, child_group_id is non-NULL.

How to delete records from parent table which is referenced by multiple child tables?

I have a table which is referenced by multiple tables (around 52) and further,few of the child tables have multiple foreign keys also that is referencing other tables too.
I want to delete a record from parent table, I am unable to do so, as I am getting error "The DELETE statement conflicted with the REFERENCE constraint "FK_xxx". The conflict occurred in database "MyDB", table "dbo.A", column 'x'."
I want a generalized T-SQL solution which is irrespective of tables and number of references.
You have to look at the "on delete" keyword which is a part of the foreign key constraint definition.
Basically you have 4 options:
NO ACTION (does nothing)
CASCADE (deletes the child aswell)
SET NULL (sets the reference field to null)
SET DEFAULT (sets the reference field to the default value)
An example would be:
CREATE TABLE parent (
id INT NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (
id INT,
parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id)
REFERENCES parent(id)
ON DELETE CASCADE -- replace CASCADE with your choice
) ENGINE=INNODB;
(for this example and more details look here: http://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html )
If you now want to modify your constraint, you first have to drop it, and create a new one like for example:
ALTER TABLE child
ADD CONSTRAINT fk_name
FOREIGN KEY (parent_id)
REFERENCES parent(id)
ON DELETE CASCADE; -- replace CASCADE with your choice
I hope this helped. Also to mention it, you should think about maybe not really deleting your parent, and instead creating another boolean column "deleted", which you fill with "yes" if someone clicks the delete. In the "Select"-query you filter then by that "deleted" column.
The advantage is, that you do not lose the history of this entry.
Your problem is this: A FK constraint is designed to prevent you from creating an orphaned child record in any of the 52 tables. I can provide you with the script you seek, but you must realise first that when you try to re-enable the FK constraints the constraints will fail to re-enable because of the orphaned data (which the FK constraints are designed to prevent). For your next step, will have to delete the orphaned data in each of the 52 tables first anyway. It is actually much easier just to redo the constraints with ON DELETE CASCADE, or drop the constraints and forget about referential integrity altogether. You can't have it both ways.

Why can't I add this foreign key?

I'll post only the main part. I have two tables, each one has to have the PK of the other as a FK.
CREATE TABLE apartment
(
cod_apartment INT NOT NULL PRIMARY KEY,
cod_offer INT NOT NULL
);
CREATE TABLE offer
(
cod_offer INT NOT NULL PRIMARY KEY,
cod_apartment INT NOT NULL
);
First I inserted the values on both tables and it was working, I could even search using "select * from...". But then I tried to add the foreign key:
This worked.
ALTER TABLE offer
ADD FOREIGN KEY (cod_apartment ) REFERENCES apartment;
And this not.
ALTER TABLE apartment
ADD FOREIGN KEY (cod_offer) REFERENCES offer;
This is the error message:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK__apartment__cod_offer__6383C8BA". The conflict occurred in database "kleber_apartment", table "dbo.offer", column 'cod_offer'.
The problem is, every time I try to execute, the FK name changes. And this FK actually doesn't exist. I already dropped both tables and tried to insert the values again, but the same happens.
What could be?
That means you're trying to add a foreign key when existing data doesn't obey that constraint. So you have a record in your apartment table where the cod_offer column does not match any value in the cod_apartment table.
Adding a foreign key not only constrains future data, but it requires that any existing data must also follow the rule.
And regarding the 6383C8BA, whenever you add a constraint without giving it a name, SQL Server picks one for you. Personally, I'd recommend something like:
alter table dbo.apartment
add constraint FK_apartment__cod_offer
foreign key (cod_offer) references dbo.offer (cod_offer);
This lets you define names the way you want, and is a little more clear about what you're actually building.

Should a foreign key be created on the parent table or child table?

What's the difference? If I have these two tables:
CREATE TABLE Account (Id int NOT NULL)
CREATE TABLE Customer (AccountId int NOT NULL)
And I want a foreign key linking the two, which of the following should I do and why?
Option 1:
ALTER TABLE [dbo].[Customer] WITH CHECK
ADD CONSTRAINT [FK_Accounts_Customers] FOREIGN KEY([AccountId])
REFERENCES [dbo].[Account] ([Id])
Option 2:
ALTER TABLE [dbo].[Account] WITH CHECK
ADD CONSTRAINT [FK_Accounts_Customers] FOREIGN KEY([Id])
REFERENCES [dbo].[Customer] ([Id])
Depends on context. Does every customer have a client? Which one is the parent? It seems like an Account has multiple Customers, in which case the reference belongs on the Customer table.
Now, that said, please call the entities CustomerID and AccountID everywhere. It may seem redundant on the primary table but the name should be consistent throughout the model.
I would use a foreign key from the child to the parent. The tell tale question is: what happens if you need to delete one of the entities?
A FK (foreign key) tells the DBMS that values for subrows for a column list must appear elsewhere as values for subrows for a column list. Whenever that happens (and it isn't already implied by other declartions) declare the FK. If in addtion you want a CASCADE action applied to the referenced table on a change to the referencing table, declare that.
(There's nothing special about CASCADE that it couldn't be offered for non-FK situations. It just comes up frequently with FKs, and there's an explicit graph of FKs by which to reasonably restrict their interactions.)
If there is a FK cycle then you will need to use triggers. Your decision of which constraint(s) are enforced declaratively & which by trigger should consider the graph of (desired) constraints.

SQL delete query with foreign key constraint

I know that this question belongs to the very early stages of the database theory, but I have not encountered such a problem since several months. If someone has a database with some tables associated together as "chain" with foreign keys and they want to delete a record from a table which has some "dependent" tables, what obstacles arise? In particular, in a database with tables: Person, Profile, Preference, Filter exist the associations as Person.id is foreign key in Profile and Profile.id is foreign key in Preference and Filter.id is foreign key in Preference, so as that all the associationsenter code here are OneToMany. Is it possible to delete a Person with a simple query:
Delete from Person p where p.id= 34;
If no, how should look like the query in order to perform the delete successfully?
If the database in the application is managed by hibernate, what constraints (annotations) should I apply to the associated fields of each entity, so as to be able with the above simple query to perform the delete?
FOR SQL VERSION
Look at the Screenshot. you can use the Insert Update Specificaiton Rules. as it has Delete and Update Rules. you can set either of these values.
Foreign key constraints may be created by referencing a primary or unique key. Foreign key constraints ensure the relational integrity of data in associated tables. A foreign key value may be NULL and indicates a particular record has no parent record. But if a value exists, then it is bound to have an associated value in a parent table. When applying update or delete operations on parent tables there may be different requirements about the effect on associated values in child tables. There are four available options in SQL Server 2005 and 2008 as follows:
No Action
Cascade
SET NULL
SET Default
Use this article for Refrence.
http://www.mssqltips.com/sqlservertip/2365/sql-server-foreign-key-update-and-delete-rules/
ORACLE VERSION
you can use one of below.
alter table sample1
add foreign key (col1)
references
sample (col2)
on delete no action;
alter table sample1
add foreign key (col1)
references
sample (col2)
on delete restrict;
alter table sample1
add foreign key (col1)
references sample (col2)
on delete cascade;
for refrance.
http://docs.oracle.com/cd/B19306_01/server.102/b14200/clauses002.htm
answer is no if there is foreign key constraint then you have to delete leaf node table data first
that is first delete from Preference table
then from Profile and Filter Table
then delete record from Person table
This is the generic concept that you apply anywhere