SQL Server : setting foreign key to a specific value - sql-server

I'm not sure what is the best way to structure my question.
I have a table with foreign key column in it. By default the foreign key is set to NOT NULL and I want to keep it that way for now, because maybe this will be the final result. But for now there could be records that don't need (and have) foreign keys values and I want to distinct them somehow so it is as clear as possible that these records are something different from the other.
I tried but as it seems I can not use negative numbers for bigint which is the value of the foreign key in my SQL Server table. I guess this is pretty standard stuff so what is the best thing to do in this situation besides making the foreign key to NULL?

Not sure why HABO didn't make that the answer, because that's pretty much your only option.
Make it NULL
Create a row in the referenced table and set it to TBD or whatever moniker you prefer and use the ID from that instead of NULL
If you have records that do not need an FK and never will, then you should set the column to NULL, else use a temp value.
You cannot use a negative value because you MUST reference something in the foreign table if you have a foreign key constraint.

Foreign key constraints enforces you to refer an existing PK of the other table.
One way not mentioned yet is to drop the constraint for now :
ALTER TABLE YourTable
DROP CONSTRAINT fk_something

Related

Update table primary key and propagate changes to other tables

I have Table A with Column A1Id as primary key, Column A1 and Column A2.
I have Table B with Column A1Id as foreign key, Column B1, and Column B2.
I have Table C with Column AI1d as foreign key, Column C1, and Column C2.
How can i update all the columns with a single command?
How can i propagate changes to all foreign keys if i update the primary key?
I'm new to SQL is this a trivial task?
I'm currently having difficulty updating a single table because of the foreign key constraint.
How can i update all the columns with a single command?
How can i propagate changes to all foreign keys if i update the primary key?
is this a trivial task?
You can't do this with a single command, it is not a trivial task, it typically takes a script of sql commands with the changes repeated for each table; usually involving UPDATEs and new columns to "migrate" the old data to the new format. Changing primary keys is something that is done very infrequently, and is almost always considered a major change even when the specifics of that change are fairly minor.
The closest (physical) analogy I can think of offhand is trying to take something apart and replace all it's screws with bolts.
Edit: If you are just talking about changing the values, not the fields or data type of the values, used as primary keys; then R VISHAL's answer is pointing in the right direction. You'll need to drop all your current constraints and recreate them to cascade the updates. You can also disable foreign key checks, change the values and then re-enable foreign key checks; but that is generally not recommended as re-enabling them does not recheck them, so if your updates put the data in an inconsistent state, it will not be corrected or even detected; and the setting is global, so any other activity going on will also be free to ignore their own fk constraints.
... but you shouldn't typically be changing primary key values either. If the value changes, it probably isn't a good candidate for a foreign key; and if it is a synthetic value (like an auto-incremented id) then you should almost never be changing it (many newer users are tempted to try to "condense" them when holes appear, but it is seldom a good idea.)
If, in your case, table B(A1id) and table C(A1id) both reference table A(A1id), then to propagate either update or delete operations to all foreign keys of tables B,C they should have the CASCADE constraint in them. In MySQL, for example, you could do this:
ALTER TABLE B
ADD CONSTRAINT FKA
FOREIGN KEY B(A1id)
REFERENCES A(A1id)
ON UPDATE CASCADE
ON DELETE CASCADE
Notice the word cascade. Is this what u want or am I missing something here? :/

Is it necessary to define on a FOREIGN KEY the same constraints that are defined on the PRIMARY KEY (parent table)?

Let's say I create a table Clients. I define a primary key and a set of constraints, such as:
NOT NULL
Length > 5
UPPERCASE
and so on..
Now, I create another table, with a foreign key to Clients primary key.
Should I create the same CONSTRAINTS for the foreign key?
If I don't it wouldn't matter, since the value won't exist on the primary table in the first place:
Example: I don't create the constraints on the foreign key, and I try to add a value which length is lower than 5 characters, and is lowercase... The database will not find that value on the parent table, hence the value will not be recorded, so what is the point of setting the same set of constraints on the foreign table?
At least you should keep the Foreign key column as not null. Otherwise, you can have many NULL values coming into the child table.
Again, as #Dale Burrell, mentioned, PRIMARY KEY should be system generated, to enforce uniqueness. If you are going to create clustered index on the primary key column, it should be narrow, incrementing, not null, unique value for getting good performance.
You don't need the length or uppercase constraints on the foreign key. They'll be "implicitly checked" by the foreign key constraint (as you say, because the referenced data cannot exist).
But for nullability, it's a choice. In SQL Server, if one or more columns in the referencing table of a foreign key are NULL, the constraint isn't enforced.
So here, the question should instead be - are there rows in the other table which should validly not reference a row in the Clients table?
Others have advised that the PK should be system generated. Whilst I agree that it's often useful to do so, don't forget to also enforce the constraints on the real data. E.g. even if this column doesn't end up being your PK, maybe it needs a unique constraint on it to ensure that you don't end up with duplicates in your data.

To use or not to use identity on a lookup table

In SQL Server I have the following lookup table that holds degree levels:
create table dbo.DegreeLevel
(
Id int identity not null
constraint PK_DegreeLevel_Id primary key clustered (Id),
Name nvarchar (80) not null
constraint UQ_DegreeLevel_Name unique (Name)
)
Should I use identity on the ID?
When should I use identity or a simple int in a lookup table?
After dealing with multiple environments where we move changes from one environment to the next, I'd say not to use identity columns on look up tables.
Here's why: if you need to reference an ID as a "magic #", you need consistency. Ideally, you wouldn't ever reference a magic #, but in reality, that is not what is commonly done. And it's a pain to correct when the IDs are out of sync. And it's really not much more effort to insert the table's data with an ID.
In a lookup table, having a "normal" Id INT might be better, because it gives you the ability to pick and choose the Id values. You get to define which values you have, and what they mean.
Identity is very useful for actual data tables, where you just need to know that you have a good, unique ID value - but you don't really care about what that value is.
I guess it comes down to whether or not you have a natural candidate to use in the clustered index...
If you already have a property that can uniquely identify the row, then its definitely worth considering whether adding an identity column is the right move.
If you don't have a natural candidate, then you'd need to invent a value and in this case using an identity column or sequence is probably easier than hand-rolling something.
As an example of having a natural key, imagine a 'DegreeModule' table where each module had a 4-character reference code that was printed on course materials (e.g. U212)
In this case, I would definitely skip creating an internal identifier and use the natural identifier as primary key...
create table dbo.DegreeModule
(
Reference char(4) not null primary key clustered,
Name nvarchar(80) not null
constraint UQ_DegreeModule_Name unique (Name)
/* .. plus FK's for stuff like parent degree, prerequisites,etc .. */
)
When you specify Identity property on an integer column on any table, the column becomes an auto-incrementing integer column. If you want your lookup table to create the id value automatically when you insert any row, use identity. if you want to create it yourself, just define the column as int.
A Table can only have one identity column
You cannot manually insert / update values in an identity column unless you specify SET identity_insert on
If you are going to use some object relational mapping (ORM) tool, refer to its documentation. In that case, you most probably would like to allow ORM to handle the primary key and you should not use identity.
If you have no specific requirements for primary key generation, then using identity here is fine. Specific requirements may be: primary keys follow special format, primary keys should be globally unique, primary keys are imported from other database, e.g. by insert into DegreeLevel values (1, 'Bachelor') etc.

Handle primary key - foreign key tables insertion?

Suppose I have two tables (primary key -> foreign key) where one record in primary key table corresponds to many record in foreign key, so if I want to make insert page (using ASP.NET for instance) for both primary key table and foreign key table, how can I get the primary key value to insert it into the foreign key table?
(usually I took the max(of PK) but I am curious to find better solution)
I assume you are using SQL Server, since you mention the use of ASP.NET. Using Max(PK) is not a good idea in a multi-user system because eventually you will end up getting an incorrect primary key value. There are also resource issues to consider. In general, this approach should be avoided.
There are several ways you can accomplish what you want to do. One way is to do your inserts via stored procedures. The stored procedure for creating the primary key row would return the Id value of the new row, which then can be used for inserting your foreign key rows. But don't use Max(PK Value). Use the SCOPE_IDENTITY() value. This assumes you are using an Identity type for your PK values. You don't state what you are actually using.

Delete a table referenced by a foreign keys

What is the best way to delete a table referenced by a foreign keys?
Is the intended goal to orphan those records and never use the foreign key again? If so the method mentioned before about disabling the key is fine, otherwise you may want to instead delete the records referencing the table you want to delete first (or update the to point to a more appropriate record, or NULL if that makes sense in this case). I seem to be coming at this from a different direction than others, are you sure the foreign key is pointless, and if so why not just remove it? At some point someone wanted to constraint this behavior, before just disabling constraints I make sure I understand their purpose and have a good justification for bypassing those safeguards.
Remove the foreign key constraint and then delete the table once no-one is forced to recognize it. If the column in the second table (the one not being deleted) is not used elsewhere, then you should probably delete the whole column after removing the constraint.
You need to remove the constraint before you're allowed to delete the table referenced by it. SQL Server uses the following syntax:
ALTER TABLE <table_name> DROP FOREIGN KEY <foreignkey_name>
Keep in mind that the constraint exists on the table that references the one you want to delete so that's the table you should be altering.
Do NOT delete a table with foreign key constraints without considering the impact on the foreign key tables. Let me explain the impact of simply deleting the foreign key and then the table with an example.
Consider two tables - parts and orderdetails. There is a foreign key constraint that says a part must exist before it can be put into the orderdetails table. What is stored in the orderdetail table is the id for the part from the parts table, not the part name or description. Suppose you drop the foreign key and then drop the parts table. Now all the data in the orderdetail table is totally useless because you have no way of knowing what the part ordered was. This would include orders not yet shipped and orders that the customer might call and ask questions about. Further you now have no way to recreate that data except by restoring a backup (hope you have one).
Further suppose you want to drop the table and recreate it to make a change to the table. Then reload the information and put the foreign key back on. In this case you should probaly use alter table instead of drop and recreate but if you don't you may end up with id numbers that are not the same as they were originally and thus now the orders will reference the wrong ids. This can be done safely but you would have to do it very carefully and with a lot of thought as to the consequences.
by using On Delete Cascade

Resources