Database table id-key Null value and referential integrity - sql

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.

Related

Why am I getting an Integrity Constraint (parent key not found) when the parent key exists

I have a parent record in my people table, but when trying to insert a matching record in my employee table, I get a integrity constraint error. Can anyone explain what is wrong?
Ah! Based on your comment:
I've added a pic of the foreign keys, personID is present is both the employee table and customer table and references the people table
it seems that you're mistaken.
Oracle doesn't check whether constraints exist, but whether data (that support those constraints) exist. In other words, first you have to insert a row into a parent table, and then into its child table (whose values "reference" primary key values in the parent table).
The way you posted it, you're inserting into child with no parent.
From the provided images, I can only guess that you are trying to insert a record into "Employee" table with "PersonId" that does not exist in the parent table "People"
If that is not the case, are you able to show us the whole table design including foreign keys?

Bypass database constraints during record deletion

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.

Swap two values in an indexed field

Is there a simple way (using a SQL query or VBA with a DAO recordset) to swap two values in an indexed field? In my case said field is the primary key of a small table (not expected to exceed 30 records). Expected input and output below.
Before:
StageNumber | Description
------------+--------------------------
01 | First Thing
02 | Second Thing
After:
StageNumber | Description
------------+--------------------------
02 | First Thing
01 | Second Thing
I'm aware this looks like I could simply switch the descriptions rather than the StageNumber but the StageNumber is used as a foreign key into another table with cascading updates specified in the relationship so simply switching the description would cause 'child' records to be associated with the wrong 'parent'.
Ideally this would be achieved with a single UPDATE..SET query but for the life of me I can't figure out what the syntax for such an operation would be without causing a primary key violation error.
This highlights one of the perils of using a Natural Keys as a primary key, when there is a risk of change of identity.
Assuming there might be similar changes in future, an alternative is to add a new Surrogate PK to the Stage table (e.g. ID as an integer AUTONUMBER), and then:
Add a new StageId foreign key column to all tables referencing Stage.
Then update the StageId column to assign the correct StageId via a lookup join via the existing foreign key (StageNo)
Then drop the FOREIGN KEY constraint on the existing StageNumber foreign key columns in the referencing tables.
Drop the PRIMARY KEY on Stage.StageNumber and change the PK to Stage.Id
Then re-add the FOREIGN KEY constraint on the new StageId foreign key columns in the referencing tables.
You are now free to change the value of the StageNumber column as it is no longer part of a foreign key.
Update StageNumber of the first record to an arbitrary number not in use.
Update StageNumber of the second record to that the first record had.
Update StageNumber of the first record to that the second records had.
Or, in two steps:
Update both StageNumbers to arbitrary numbers not in use.
Update both StageNumbers to that the other record had.

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

Is it possible to change SQL user-defined data type?

I have a bunch of tables using user-defined data type for PK column. Is it possible to change this type Using SQL Server 2005?
I would suggest that it is always possible to refactor poor or outmoded database designs, it simply depends on how much work you are willing to go to in order to do so.
If you are looking to replace the user-defined data with a surrogate key then you should be able to simply alter the existing table to contain a non-nullable identity column and this should cause all of the existing records to be assigned a new key automatically.
Once the new field is populated with unique id's, if you need to move out and replace foreign key references to this table, then I would simply alter those tables to contain the new field and use something like the following:
UPDATE child_table
SET new_fk_val =
SELECT new_pk_val
FROM parent_table
WHERE parent_table.old_pk_val = child_table.old_fk_val
Once that step is complete, then you could drop the old foreign key constraint, drop the old foreign key column, drop the old primary key column, establish the new primary key constraint, and then establish the new foreign key constraint.
Of course, if the old version of the parent and child tables relationship was such that you have invalid records in the child table you may have to do something like the following:
DELETE FROM child_table
WHERE old_fk_val NOT IN
( SELECT old_pk_val FROM parent_table)