SQL Server Conditional Foreign Key Constraints - sql-server

I'm having trouble figuring out how to create a foreign key constraint. My data model is fixed and out of my control, it looks like this:
CREATE TABLE Enquiry
(Enquiry_Ref INTEGER PRIMARY KEY CLUSTERED, Join_Ref INTEGER, EnquiryDate, EnquiryType...)
CREATE TABLE Contact
(Contact_Ref INTEGER PRIMARY KEY CLUSTERED, Surname, Forenames ....)
CREATE TABLE UniversalJoin
(Join_Ref INTEGER, Contact_Ref INTEGER, Rel_Type INTEGER)
Each Enquiry has exactly one Contact. The link between the two is the UniversalJoin table where
Enquiry.Join_Ref = UniversalJoin.Join_Ref AND
Rel_Type = 1 AND
UniversalJoin.Contact_Ref = Contact.Contact_Ref
The Rel_Type differs depending on what the source table is, so in the case of Enquiry, Rel_Type is 1 but for another table it would set to N.
My question is how do I create a foreign key constraint to enforce the integrity of this relationship? What I want to say, but can't, is:
CREATE TABLE Enquiry
...
CONSTRAINT FK_Foo
FOREIGN KEY (Join_Ref)
REFERENCES UniversalJoin (JoinRef WHERE Rel_Type=1)

You can't use conditional or filtered foreign keys in SQL Server
In these cases, you could have a multiple column FK between (JoinRef, Rel_Type) and set a check constraint on Rel_Type in UniversalJoin to make it 1.
However, I think you are trying to have a row with multiple parents which can't be done.

You might rather want to have a look at CHECK Constraints
CHECK constraints enforce domain
integrity by limiting the values that
are accepted by a column. They are
similar to FOREIGN KEY constraints in
that they control the values that are
put in a column. The difference is in
how they determine which values are
valid: FOREIGN KEY constraints obtain
the list of valid values from another
table, and CHECK constraints determine
the valid values from a logical
expression that is not based on data
in another column.

You could use a table trigger with INSERT and Update to layer the equivalent as a FK.
This way you are able to apply conditions i.e. if column value =1 check exists in table a if column value = 2 then check another table.

Related

Adding a primary key column to an existing table in SQL Server?

I need to add a new column and make it the primary key in SQL Server; the table in question does not yet have a unique key column.
Here is the sample table http://www.sqlfiddle.com/#!18/8a161/1/0
My goal is simply to have a column ID and insert values from 1 to 1160 (total number of records in this table) and make that the primary key. Also is there a way to automatically add the numbers from 1-1160 without adding each record one by one since there are 1000+ rows in this table?
Thank you!
Simply alter the table and add the column with the appropriate characteristics.
alter table x add id smallint identity(1,1) not null primary key;
Thrown together quickly and you probably should get in the habit of naming constraints. fiddle. I will note that you may or may not want to use an identity column - think carefully about your actual goal and how you want to continue using this table after the alteration.

check table and foreign key table check

The system correctly set the foreign key (zemploy01-department) with the check table (zdepartmentt02-department) - inside the red box in the diagram. If i do a system check, the system says: zemploy01-department is consistant.
It is apparent that the system takes all primary keys from the check table, and tries to match it to the keys of the foreign key table. The primary key columns of check table(zdepartmentt02) are: MANDT, CAREER, DEPARTMENT, LANGUAGE. These are matched to MANDT, CAREER, DEPARTMENT columns of the foreign key table(zemploy01). However, only one column should be matched i.e. zdepartmentt02-department and zemploy01-department. Why is the system trying to match all the primary keys of the check table.
The values filled in on this wizard are the fields you have set as primary keys in the check table

Is it possible to arrange a foreign key constraint for data in XML?

Some node values inside of XML column reference integer primary keys of known tables. Is it possible to make SQL Server to check this kind of foreign key relationship?
The answer is yes, you can!
With the constraint that your document contains a fixed number of such references you can create persisted computed columns for you foreign key as such.
CREATE FUNCTION dbo.GetFooRef(#doc XML)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
RETURN #doc.value(N'(/doc/foo/#id)[1]','int');
END;
CREATE TABLE Foo(id INT PRIMARY KEY);
CREATE TABLE Bar(
doc XML,
ref AS (dbo.GetFooRef(doc)) PERSISTED FOREIGN KEY REFERENCES dbo.Foo(id)
);
INSERT INTO dbo.Bar(doc) VALUES ('<doc><foo id="1"/></doc>');
--The INSERT statement conflicted with the FOREIGN KEY constraint "FK__Bar__ref__ ..."
INSERT INTO dbo.Foo(id) VALUES (1);
INSERT INTO dbo.Bar(doc) VALUES ('<doc><foo id="1"/></doc>');
The answer is no, you can't.
You can't directly use an XML value() in a FOREIGN KEY relationship. For the fun of it I tried creating a computed column that has the result of calling .value('<some xpath>', 'int') wrapped in a user-defined function. The trouble with that is you also can't use a computed column in a FOREIGN KEY relationship.
Outside of an actual constraint you could attempt to perform validation of incoming INSERT and UPDATE statements in a trigger...but this is already becoming a mess of a solution. As Damien says - this really doesn't belong in an XML document if you want to enforce a foreign key constraint.
I would post that as a comment but I don't have enough reputation :D. I think you can add a constraint returning the value of a function that would valid whatever you want in your xml. It would not be a Foreign key but it would at least check your integrity.

SQL Server: Unable to create relationship

I was trying to create a table that has a one to many relationships. but it seems that adding a foreign key in Personal is not working. I am trying to link a Personal Information table to a address table? what is the solution for this error?
Address table saved successfully
Personal table
Unable to create relationship 'FK_Personal_Address'.
Cascading foreign key 'FK_Personal_Address' cannot be created where the
referencing column 'Personal.ID' is an identity column. Could not
create constraint. See previous errors.
The primary key in the Person table is presumably an identity. This is an auto-incrementing integer field.
You need to make the foreign key in the address table of type int, not identity. It will hold integers which correspond to Person records, but you don't want the foreign key to auto-increment. For each record in the child table (address) you will set a specific value for the foreign key indicating to which parent record (Person) it belongs.
Example:
INSERT person (firstname, lastname) VALUES ('John', 'Smith')
This will insert the new person record and the field personid will be filled automatically because it is an IDENTITYfield.
Now to insert an address from John Smith you need to know his personid. For example:
-- Say, for example, personid of John Smith is 55
INSERT address (personid, street, city) VALUES (55, 'High Street', 'London')
So in the person table the personid is generated automatically but in the address table you specify the value that matches an existing person. That's the whole point of a foreign key.
Without more information about your schema it's hard to guess the problem.
I made sure to follow identity, int and primary key discussed in above answer. However, I was still getting the same error.
'xReason' table saved successfully
'xAddress' table
- Unable to create relationship 'FK_xAddress_xReason'.
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_xAddress_xReason". The conflict occurred in database "databaseName", table "dbo.xReason", column 'xReasonID'.
This error resolved when I inserted some data into a Reason table. (table that had a primary key)
If you read this far, this might be your problem.
Without seeing the structure of the tables in the question, I believe the most likely cause is the column in your child table (Address) is marked as an Identity column. In a foreign-key relationship, the parent determines the value of the field, not the child. The column may be the PK in the child table, but not an Identity.
it seem that you try to create a foreign key on Personal.ID related to itself.
You probably want to do something like :
ALTER TABLE Adress WITH NOCHECK ADD CONSTRAINT [FK_Adress_Personnal] FOREIGN KEY(Personal_Id)
REFERENCES Personal (ID)
I got the same error with adding foreign key constraints to one of my tables.
I found the workaround was to add it WITH NOCHECK. why I was able to add the other two foreign keys WITH CHECK but not the third foreign? I found that it was not the table but the order of the foreign key to be added. Any insight to this will be much appreciated.

Are foreign keys indexed automatically in SQL Server?

Would the following SQL statement automatically create an index on Table1.Table1Column, or must one be explicitly created?
Database engine is SQL Server 2000
CREATE TABLE [Table1] (
. . .
CONSTRAINT [FK_Table1_Table2] FOREIGN KEY
(
[Table1Column]
) REFERENCES [Table2] (
[Table2ID]
)
)
SQL Server will not automatically create an index on a foreign key. Also from MSDN:
A FOREIGN KEY constraint does not have
to be linked only to a PRIMARY KEY
constraint in another table; it can
also be defined to reference the
columns of a UNIQUE constraint in
another table. A FOREIGN KEY
constraint can contain null values;
however, if any column of a composite
FOREIGN KEY constraint contains null
values, verification of all values
that make up the FOREIGN KEY
constraint is skipped. To make sure
that all values of a composite FOREIGN
KEY constraint are verified, specify
NOT NULL on all the participating
columns.
As I read Mike's question, He is asking whether the FK Constraint will create an index on the FK column in the Table the FK is in (Table1). The answer is no, and generally. (for the purposes of the constraint), there is no need to do this The column(s) defined as the "TARGET" of the constraint, on the other hand, must be a unique index in the referenced table, either a Primary Key or an alternate key. (unique index) or the Create Constraint statment will fail.
(EDIT: Added to explicitly deal with comment below -)
Specifically, when providing the data consistency that a Foreign Key Constraint is there for. an index can affect performance of a DRI Constraint only for deletes of a Row or rows on the FK side. When using the constraint, during a insert or update the processor knows the FK value, and must check for the existence of a row in the referenced table on the PK Side. There is already an index there. When deleting a row on the PK side, it must verify that there are no rows on the FK side. An index can be marginally helpful in this case. But this is not a common scenario.
Other than that, in certain types of queries, however, where the query processor needs to find the records on the many side of a join which uses that foreign key column. join performance is increased when an index exists on that foreign key. But this condition is peculiar to the use of the FK column in a join query, not to existence of the foreign Key constraint... It doesn't matter whether the other side of the join is a PK or just some other arbitrary column. Also, if you need to filter, or order the results of a query based on that FK column, an index will help... Again, this has nothing to do with the Foreign Key constraint on that column.
No, creating a foreign key on a column does not automatically create an index on that column. Failing to index a foreign key column will cause a table scan in each of the following situations:
Each time a record is deleted from the referenced (parent) table.
Each time the two tables are joined on the foreign key.
Each time the FK column is updated.
In this example schema:
CREATE TABLE MasterOrder (
MasterOrderID INT PRIMARY KEY)
CREATE TABLE OrderDetail(
OrderDetailID INT,
MasterOrderID INT FOREIGN KEY REFERENCES MasterOrder(MasterOrderID)
)
OrderDetail will be scanned each time a record is deleted in the MasterOrder table. The entire OrderDetail table will also be scanned each time you join OrderMaster and OrderDetail.
SELECT ..
FROM
MasterOrder ord
LEFT JOIN OrderDetail det
ON det.MasterOrderID = ord.MasterOrderID
WHERE ord.OrderMasterID = #OrderMasterID
In general not indexing a foreign key is much more the exception than the rule.
A case for not indexing a foreign key is where it would never be utilized. This would make the server's overhead of maintaining it unnecessary. Type tables may fall into this category from time to time, an example might be:
CREATE TABLE CarType (
CarTypeID INT PRIMARY KEY,
CarTypeName VARCHAR(25)
)
INSERT CarType .. VALUES(1,'SEDAN')
INSERT CarType .. VALUES(2,'COUP')
INSERT CarType .. VALUES(3,'CONVERTABLE')
CREATE TABLE CarInventory (
CarInventoryID INT,
CarTypeID INT FOREIGN KEY REFERENCES CarType(CarTypeID)
)
Making the general assumption that the CarType.CarTypeID field is never going to be updated and deleting records would be almost never, the server overhead of maintaing an index on CarInventory.CarTypeID would be unnecessary if CarInventory was never searched by CarTypeID.
According to: https://learn.microsoft.com/en-us/sql/relational-databases/tables/primary-and-foreign-key-constraints?view=sql-server-ver16#indexes-on-foreign-key-constraints
Unlike primary key constraints, creating a foreign key constraint does not automatically create a corresponding index

Resources