Bypass database constraints during record deletion - sql

I have around 20 mapping tables which refer to a single table.
The single table being referenced is,
field (
id integer,
value char
)
The mapping tables are as,
employee_field_map (
employee_id integer references employee(id),
field_id references field(id)
)
dept_field_map (
dept_id integer references dept(id),
field_id references field(id)
)
and similar additional 18 mapping tables.
Now if I want to delete number of records from the field table where field.id = employee_field_map.field_id it takes very long amount of time because there are 20 mapping tables which refer to the field table; And for each of that mapping table a constraint violation check is performed before deleting a record from the field table.
A field table rcord will always be referenced by only one of the mapping table at a time.
In above scenario before deleting a record from field table of course the corresponding record in employee_field_map table is deleted first. So I know for sure that none of the mapping table contains a reference to the field table record being deleted. So is there a way to tell the database engine not to perform those constraint checks when the delete on field table is being performed?
Disabling the constraints is not an option unfortunately. Please advise.

Assuming each of the mapping tables has an index on field_id, then the lookups should not be expensive.
I am wondering why you are not declaring them using cascading delete foreign key references:
employee_field_map (
employee_id integer references employee(id),
field_id references field(id) on delete cascade
);
Nothing in your data model is saying that the field is in only one mapping table. In fact, I don't see why things are broken out the way they are. Presumably there is a reason for breaking the fields apart like this instead of just having a "type" column in the fields table.

Related

Create a table with a foreign key referencing to a temporary table generated by a query

I need to create a table having a field, which is a foreign key referencing to another query rather than existing table. E.g. the following statement is correct:
CREATE TABLE T1 (ID1 varchar(255) references Types)
but this one throws a syntax error:
CREATE TABLE T2 (ID2 varchar(255) references SELECT ID FROM BaseTypes UNION SELECT ID FROM Types)
I cannot figure out how I can achieve my goal. In the case it’s needed to introduce a temporary table, how can I force this table being updated each time when tables BaseTypes and Types are changed?
I am using Firebird DB and IBExpert management tool.
A foreign key constraint (references) can only reference a table (or more specifically columns in the primary or unique key of a table). You can't use it to reference a select.
If you want to do that, you need to use a CHECK constraint, but that constraint would only be checked on insert and updates: it wouldn't prevent other changes (eg to the tables in your select) from making the constraint invalid while the data is at rest. This means that at insert time the value could meet the constraint, but the constraint could - unnoticed! - become invalid. You would only notice this when updating the row.
An example of the CHECK-constraint could be:
CREATE TABLE T2 (
ID2 varchar(255) check (exists(
SELECT ID FROM BaseTypes WHERE BaseTypes.ID = ID2
UNION
SELECT ID FROM Types WHERE Types.ID = ID2))
)
For a working example, see this fiddle.
Alternatively, if your goal is to 'unite' two tables, define a 'super'-table that contains the primary keys of both tables, and reference that table from the foreign key constraint. You could populate and update (eg insert and delete) this table using triggers. Or you could use a single table, and replace the existing views with an updatable view (if this is possible depends on the exact data, eg IDs shouldn't overlap).
This is more complex, but would give you the benefit that the foreign key is also enforced 'at rest'.

SQLite Drop Column and Cascading Delete

I have researched how to drop a column using SQLite. Due to the lack of a DROP COLUMN statement, I am considering using the following workaround:
Delete column from SQLite table
This involves moving all data into a temporary table, dropping the original, and then re-creating it.
If I have a cascading delete dependency on the table I want to modify, how can I prevent any dependent tables from losing data?
Ex.
CREATE TABLE A (
id INTEGER PRIMARY KEY,
name TEXT,
dummy INTEGER
)
CREATE TABLE B (
id INTEGER PRIMARY KEY,
name TEXT,
a_id INTEGER,
FOREIGN KEY (a_id) REFERENCES A(id) ON DELETE CASCADE
)
Let's say I want to remove Column "dummy" from Table A, but I don't want to affect any rows in Table B. Can this be done?
Foreign key constraints can be disabled with a PRAGMA.
Just execute PRAGMA foreign_keys = off before removing records.
Cascading Deletes are based on records (rows) not attributes (columns). Removing the dummy column will not cause any cascading deletes as you are not removing any records from the parent table.

ON UPDATE CASCADE with two columns in a single table in SQL Server [duplicate]

I have a database table called Lesson:
columns: [LessonID, LessonNumber, Description] ...plus some other columns
I have another table called Lesson_ScoreBasedSelection:
columns: [LessonID,NextLessonID_1,NextLessonID_2,NextLessonID_3]
When a lesson is completed, its LessonID is looked up in the Lesson_ScoreBasedSelection table to get the three possible next lessons, each of which are associated with a particular range of scores. If the score was 0-33, the LessonID stored in NextLessonID_1 would be used. If the score was 34-66, the LessonID stored in NextLessonID_2 would be used, and so on.
I want to constrain all the columns in the Lesson_ScoreBasedSelection table with foreign keys referencing the LessonID column in the lesson table, since every value in the Lesson_ScoreBasedSelection table must have an entry in the LessonID column of the Lesson table. I also want cascade updates turned on, so that if a LessonID changes in the Lesson table, all references to it in the Lesson_ScoreBasedSelection table get updated.
This particular cascade update seems like a very straightforward, one-way update, but when I try to apply a foreign key constraint to each field in the Lesson_ScoreBasedSelection table referencing the LessonID field in the Lesson table, I get the error:
Introducing FOREIGN KEY constraint 'c_name' on table 'Lesson_ScoreBasedSelection' may cause cycles or multiple cascade paths.
Can anyone explain why I'm getting this error or how I can achieve the constraints and cascading updating I described?
You can't have more than one cascading RI link to a single table in any given linked table. Microsoft explains this:
You receive this error message because
in SQL Server, a table cannot appear
more than one time in a list of all
the cascading referential actions that
are started by either a DELETE or an
UPDATE statement. For example, the
tree of cascading referential actions
must only have one path to a
particular table on the cascading
referential actions tree.
Given the SQL Server constraint on this, why don't you solve this problem by creating a table with SelectionID (PK), LessonID, Next_LessonID, QualifyingScore as the columns. Use a constraint to ensure LessonID and QualifyingScore are unique.
In the QualifyingScore column, I'd use a tinyint, and make it 0, 1, or 2. That, or you could do a QualifyingMinScore and QualifyingMaxScore column so you could say,
SELECT * FROM NextLesson
WHERE LessonID = #MyLesson
AND QualifyingMinScore <= #MyScore
AND #MyScore <= QualifyingMaxScore
Cheers,
Eric

Database table id-key Null value and referential integrity

I'm learning databases, using SQLce. Got some problems, with this error:
A foreign key value cannot be inserted because a corresponding primary key value does not exist.
How does the integrity and acceptance of data work when attempting to save a data row that does not have specified one foreign key. Isn't it possible to set it to NULL in some way, meaning it will not reference the other table? In case, how would I do that? (For an integer key field)
Also, what if you save a row with a valid foreign key that corresponds to an existing primary key in other table. But then decide to delete that entry in this other table. So the foreign key will no longer be valid. Will I be allowed to delete? How does it work? I would think it should then be simply reset to a null value.. But maybe it's not that simple?
What you need to do is insert your data starting from the parent down.
So if you have an orders table and an items table that refers to orders, you have to create the new order first before adding all the children to the list.
Many of the data access libraries that you can get (in C# there is Linq to SQL) which will try and abstract this problem.
If you need to delete data you actually have to go the other way, delete the items before you delete the parent order record.
Of course, this assumes you are enforcing the foreign key, it is possible to not enforce the key, which might be useful during a bulk delete.
This is because of "bad data" you have in the tables. Check if you have all corresponding values in the primary table.
DBMS checks the referential integrity for ensuring the "correctness" of data within database.
For example, if you have a column called some_id in TableA with values 1 through 10 and a column called some_id in TableB with values 1 through 11 then TableA has no corresponding value (11) for that which you have already in TableB.
You can make a foreign key nullable but I don't recommend it. There are too many problems and inconsistencies that can arise. Redesign your tables so that you don't need to populate the foreign key for values that don't exist. Usually you can do that by moving the column to a new table for example.

General many-to-many relationship problem ( Postgresql )

i have two tables:
CREATE TABLE "public"."auctions" (
"id" VARCHAR(255) NOT NULL,
"auction_value_key" VARCHAR(255) NOT NULL,
"ctime" TIMESTAMP WITHOUT TIME ZONE NOT NULL,
"mtime" TIMESTAMP WITHOUT TIME ZONE NOT NULL,
CONSTRAINT "pk_XXXX2" PRIMARY KEY("id"),
);
and
CREATE TABLE "public"."auction_values" (
"id" NUMERIC DEFAULT nextval('default_seq'::regclass) NOT NULL,
"fk_auction_value_key" VARCHAR(255) NOT NULL,
"key" VARCHAR(255) NOT NULL,
"value" TEXT,
"ctime" TIMESTAMP WITHOUT TIME ZONE NOT NULL,
"mtime" TIMESTAMP WITHOUT TIME ZONE NOT NULL,
CONSTRAINT "pk_XXXX1" PRIMARY KEY("id"),
);
if i want to create a many-to-many relationship on the auction_value_key like this:
ALTER TABLE "public"."auction_values"
ADD CONSTRAINT "auction_values_fk" FOREIGN KEY ("fk_auction_value_key")
REFERENCES "public"."auctions"("auction_value_key")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
i get this SQL error:
ERROR: there is no unique constraint matching given keys for referenced table "auctions"
Question:
As you might see, i want "auction_values" to be be "reused" by different auctions without duplicating them for every auction... So i don't want a key relation on the "id" field in the auctions table...
Am i thinking wrong here or what is the deal? ;)
Thanks
You need an extra table to model a many-to-many relationship. It will contain the mappings between auctions and auction_values. It needs two columns: auction_id and auction_value_id.
If you want the auction_values to be reused by different auctions, you should declare a constraint the other way round:
ALTER TABLE auctions
ADD CONSTRAINT fk_auction_values
FOREIGN KEY (auction_value_key)
REFERENCES auction_values (id)
Quoting the wikipedia
In the context of relational
databases, a foreign key is a
referential constraint between two
tables.1 The foreign key identifies
a column or a set of columns in one
(referencing) table that refers to set
of columns in another (referenced)
table. The columns in the referencing
table must be the primary key or other
candidate key in the referenced table.
The values in one row of the
referencing columns must occur in a
single row in the referenced table.
Thus, a row in the referencing table
cannot contain values that don't exist
in the referenced table (except
potentially NULL). This way references
can be made to link information
together and it is an essential part
of database normalization. Multiple
rows in the referencing table may
refer to the same row in the
referenced table. Most of the time, it
reflects the one (master table, or
referenced table) to many (child
table, or referencing table)
relationship.
As Quassnoi points out, it sounds as if you want to have multiple rows in auctions reference single rows in auction_values.
For that the master or referenced table is auction_values and child or referencing table is auction_values.
If on the other hand Alex is right and you want to reference multiple rows in the auction_values you will need another table.
This table will help you convert the many-to-many relationship (which can not be directly realized on the physical database level) to two one-to-many relationships.
Generally you could have this table store ids from the two starting tables and in this way you can associate any combination of the records from auction_values and auctions.
However, this might be too general and you might actually be after a table auction_value_keys (auction_value_key)