I am currently learning SQL, and I have a physical data model I need to implement in code. However, during constraint creation, the numbers appearing next to FK and U started confusing me immensely. Consider the diagram. EDIT: Added the full physical model.
I know that when the matter is Primary Keys, we must have a single PK Constraint that's all the columns marked as PK. However, when the thing is FK or Unique constraints, I'm not so sure myself.
Let's assume I want to create the FK constraints for the table Opcao.
Should I create a single constraint for multiple columns, referencing their respective columns like this:
ALTER TABLE MySchema.Opcao ADD CONSTRAINT [FK_SUPERKEY] FOREIGN KEY ([prova], [aluno], [pergunta], [dataRealizacao])
REFERENCES MySchema.Integra([prova], [aluno], [pergunta], [dataRealizacao]);
Or create a constraint for each column, like this:
ALTER TABLE MySchema.Opcao ADD CONSTRAINT [FK_OPCAO_PROVA] FOREIGN KEY ([prova])
REFERENCES MySchema.Integra([prova]);
ALTER TABLE MySchema.Opcao ADD CONSTRAINT [FK_OPCAO_ALUNO] FOREIGN KEY ([aluno])
REFERENCES MySchema.Integra([aluno]);
ALTER TABLE MySchema.Opcao ADD CONSTRAINT [FK_OPCAO_PERGUNTA] FOREIGN KEY ([pergunta])
REFERENCES MySchema.Integra([pergunta]);
ALTER TABLE MySchema.Opcao ADD CONSTRAINT [FK_OPCAO_DATAREALIZACAO] FOREIGN KEY ([dataRealizacao])
REFERENCES MySchema.Integra([dataRealizacao]);
Would the Unique constraints follow the same logic? How do I know when to do one or the other?
You want to make a foreign key consisting of three columns which have to match all the three columns in the referenced table?
Then you should use in my oppinion on constraint for the three columns, because its the semantic you want to tell.
The one constraint for each column approach has the same effect, but you have to think a little to get the intension.
Some other tips: I don't get the semantic of the schema because i don't know the language the entities are named in. It would be easier if they were named in english. One thing i saw is the pergunta column which is duplicated and needs to be consistent in opcao, Integra und Pergunta table, this may lead to problems.
I generally helped me to always make an artifical auto increment primary key for every table (even the join tables for n to m relations), and always reference this artificial key. Then you have less problems (with case insensitivity for example) and the schema is in my oppinion easier to understand.
Related
I have a specific situation where I have a column type in my DB where the column is currently of type int and it is a foreign key type that allows nulls...
My question is: is it possible to change now this column simply to a int type which isn't a foreign key without messing up the data in both tables, and leaving the values intact?
For example:
alter table xy
alter column ForeignKeyIdColumn int null
Would something like this work?
Can someone help me out?
A foreign key is not a property of the columns of a table, it's a database object that defines the relationship between tables.
You can drop the foreign key constraint (though I wouldn't recommend it) using ALTER TABLE with DROP CONSTRAINT, but you have to know the name of the constraint to do it (this is why it's best practice to name everything in SQL SERVER):
ALTER TABLE xy
DROP CONSTRAINT <constraint name here>;
However, as I wrote, I wouldn't recommend dropping foreign key constraints.
Foreign keys are the database way to enforce referential integrity - meaning that a value referenced by another table can't be changed or deleted without changing or deleting the referencing value as well.
Dropping foreign keys means your database will not be able to enforce referential integrity any more and that might lead to corrupt data.
For more information, read Delete Foreign Key Relationships
Let's assume I have a table called boxes with the box_id attribute as the PK.
There are two other tables. The first one is red_boxes and the second blue_boxes.
I have added a constraint to the red_boxes table
ALTER TABLE red_boxes
ADD CONSTRAINT fk_box_id
FOREIGN KEY (box_id)
REFERENCES boxes (box_id);
Now, I would like to add a constraint to the blue_boxes table. The SQL structure would look like the following, if I did not add the constraint already to the the red_boxes. The obvious way to fix this is to name a new constraint differently e.g. fk_box_id2, but is this is a good way? Am I supposed to somehow re-use the previous constraint, or this is not possible, why?
ALTER TABLE blue_boxes
ADD CONSTRAINT fk_box_id
FOREIGN KEY (box_id)
REFERENCES boxes (box_id)
Each constraint is separate and requires a unique name. My recommendation is to use the source and destination table names, for example fk_red_boxes_boxes and fk_blue_boxes_boxes. This way you can easily identify where they come from and where they go to.
If you have underscores in your table names, you might want to come up with a modified convention that you can easily understand at a glance. For example, a double underscore: fk__blue_boxes__boxes and fk__red_boxes__boxes.
I went over a legacy database and found a couple of foreign keys that reference a column to itself. The referenced column is the primary key column.
ALTER TABLE [SchemaName].[TableName] WITH CHECK ADD
CONSTRAINT [FK_TableName_TableName] FOREIGN KEY([Id])
REFERENCES [SchemaName].[TableName] ([Id])
What is the meaning of it?
ALTER TABLE [SchemaName].[TableName] WITH CHECK ADD
CONSTRAINT [FK_TableName_TableName] FOREIGN KEY([Id])
REFERENCES [SchemaName].[TableName] ([Id])
This foreign key is completely redundant and pointless just delete it. It can never be violated as a row matches itself validating the constraint.
In a hierarchical table the relationship would be between two different columns (e.g. Id and ParentId)
As for why it may have been created quite likely through use of the visual designer if you right click the "Keys" node in object explorer and choose "New Foreign Key" then close the dialogue box without deleting the created foreign key and then make some other changes in the opened table designer and save it will create this sort of redundant constraint.
In some cases this is a preferred way to reduce redundancy in your model. In using the self referencing foreign key (as shown in you example) you create a hierarchical relationship between rows in your table. Pay attention to what happens when you delete a row from the table, cascading on delete might remove rows you still want.
Using these sort of keys moves some of the data validation to the DB model as opposed to making this a responsibility of the program/programmer. Some outfits prefer this way of doing things. I prefer to make sure programs and programmers are responsible - data models can be hard to refactor and upgrade in production environments.
i am quite confused about the difference between a FOREIGN KEY and CHECK constraint - they appear to me to achieve the same result.
I mean I could create a table and enforce a Foreign key on another table, but i could create a CHECK to ensure the value in in another table.
What is the difference and when to use the one or the other?
A FOREIGN KEY constrain ensures that the entry DOES EXISTS in
EDIT
another table
as per correct comment Exists in another table... or the same table. – Mark Byers
A CHECK constrain ensures that the entry follows some rule.
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.
A foreign key constraint is more powerful than a CHECK constraint.
A foreign key constraint means that the column (in the current table) can only have values that already exist in the column of the foreign table (which can include the be the same table, often done for hierarchical data). This means that as the list of values changes - gets bigger or smaller - there's no need to update the constraint.
A check constraint can not reference any columns outside of the current table, and can not contain a subquery. Often, the values are hard coded like BETWEEN 100 and 999 or IN (1, 2, 3). This means that as things change, you'll have to update the CHECK constraint every time. Also, a foreign key relationship is visible on an Entity Relationship Diagram (ERD), while a CHECK constraint will never be. The benefit is that someone can read the ERD and construct a query from it without using numerous DESC table commands to know what columns are where and what relates to what to construct proper joins.
Best practice is to use foreign keys (and supporting tables) first. Use CHECK constraints as a backup for situations where you can't use a foreign key, not as the primary solution to validate data.
It depends on your DBMS (which you didn't specify), but in one sense, you are correct: a foreign key constraint is a particular case of a check constraint. There are DBMS which would not allow you to formulate a foreign key constraint as a check constraint.
The main intention of a check constraint is to describe conditions that apply to a single row in the table. For example, I have a table of elements (as in Hydrogen, Helium, ...) and the symbols for the elements are constrained to start with an upper-case letter and are followed by zero, one or two lower-case letters (two lower-case letters for as yet undiscovered but predicted elements: Uus - ununseptium (117), which has just been isolated but has yet to be named). This can be the subject of a CHECK constraint:
CHECK(Symbol MATCHES "[A-Z][a-z]{0,2}")
assuming MATCHES exists and supports an appropriate regular expression language.
You can also have check constraints that compare values:
CHECK(OrderDate <= ShipDate OR ShipDate IS NULL)
To express a foreign key constraint as a check constraint, you have to be permitted to execute a query in the CHECK clause. Hypothetically:
CHECK(EXISTS(SELECT * FROM SomeTable AS s
WHERE ThisTable.pk_col1 = s.pk_col1 AND
ThisTable.pk_col2 = s.pk_col2))
This example shows some of the problems. I don't have a convenient table alias for the table in which I'm writing the check constraint - I assumed it was 'ThisTable'. The construct is verbose. Assuming that the primary key on SomeTable is declared on columns pk_col1 and pk_col2, then the FOREIGN KEY clause is much more compact:
FOREIGN KEY (pk_col1, pk_col2) REFERENCES SomeTable
Or, if you are referencing an alternative key, not the primary key:
FOREIGN KEY (pk_col1, pk_col2) REFERENCES SomeTable(ak_col1, ak_col2)
This is notationally more compact - so there is less chance of getting it wrong - and can be special-cased by the server because the special notation means it knows that it is dealing with a foreign key constraint whereas the general check clause has to be scrutinized to see if it matches one of many possible forms that are equivalent to the foreign key.
The question asks: when to use a check constraint and when to use a foreign key constraint?
Use a CHECK constraint to specify criteria that can be checked in a single row.
Use a FOREIGN KEY constraint to specify that the values in the current row must match the values of a row in some other unique key (a candidate key, usually the primary key rather than an alternative key) of some table - which may be the same table or (more usually) a different table.
Consider a scenario like this:
Table A has a keyword column, and the value must be among thousand of keywords provided.
How would you like to implement the constraint?
Hard coded check condition like check (keyword in ('a', 'b', 'c' .......)) or simply import the provided keywords as another table and set a foreign key constraint to keyword column of Table A.
For instance, suppose I have table A. Then I have tables B-Z that have a foreign key to table A's primary key. Then perhaps there are also some tables that have a foreign key constraint to a table in B-Z's primary key constraint. Is there any easy way to clear out table A and all of the tables that refer to A (or that refer to a table that refers to A) without having to explicitly delete from each table or add an ON CASCADE constraint to each foreign key?
Note that this is mainly for testing purposes, not to be used in production. I would just drop the entire schema and start over again, but that simply isn't feasible for every test (considering how long it takes to build the schema).
I think the most efficient way to do this would be to drop all the FK's, truncate the tables, and then rebuild the FK's.