SQL What is the Purpose of 1 to 1 self reference on primary key? [duplicate] - sql

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.

Related

Why would someone need to enable/disable constraints?

Just starting to learn basics of SQL. In some versions of SQL (Oracle, SQL server etc.) there are enable/disable constraints keywords. What is the difference between these and add/drop constraints keywords? Why do we need it?
Constraint validation has a performance penalty when performing a DML operation. It's common to disable a constraint before a bulk insert/import of data (especially if you know that data is "OK"), and then enable it after the bulk operation is done.
I use disabled constraints in a special situation. I have an application with many tables (around 1000). The records in these table have "natural keys", i.e. identifiers and relations which are given by external source. Some tables use even different natural keys as foreign key references to different tables.
But I like to use common surrogate keys as primary key and for foreign references.
Here is one example (not 100% sure about correct syntax):
CREATE TABLE T_BTS (
OBJ_ID number constraint BTS_PK (OBJ_ID) PRIMARY KEY,
BTS_ID VARCHAR2(20) CONSTRAINT BTS_UK (BTS_ID) UNIQUE,
some more columns);
CREATE TABLE T_CELL (
OBJ_ID number constraint BTS_PK (OBJ_ID) PRIMARY KEY,
OBJ_ID_PARENT number,
BTS_ID VARCHAR2(20),
CELL_ID VARCHAR2(20) CONSTRAINT CELL_UK (BTS_ID, CELL_ID) UNIQUE,
some more columns);
ALTER TABLE T_CELL ADD CONSTRAINT CELL_PARENT_FK
FOREIGN KEY (OBJ_ID_PARENT)
REFERENCES T_BTS (OBJ_ID);
ALTER TABLE T_CELL ADD CONSTRAINT CELL_PARENT
FOREIGN KEY (BTS_ID)
REFERENCES T_BTS (BTS_ID) DISABLE;
In all my tables the primary key column is always OBJ_ID and the key to parent table is always OBJ_ID_PARENT, not matter how the natural key is defined. This makes me easier to have common PL/SQL procedures and compose dynamic SQL Statements.
One example: In order to set OBJ_ID_PARENT after insert, following update would be needed
UPDATE T_CELL cell SET OBJ_ID_PARENT =
(SELECT OBJ_ID
FROM T_BTS bts
WHERE cell.BTS_ID = bts.BTS_ID)
I am too lazy to write 1000+ such individual statements. By using views USER_CONSTRAINTS and USER_CONS_COLUMNS I am able to link the natural keys and the surrogate keys and I can execute these updates via dynamic SQL.
All my keys and references are purely defined by constraints. I don't need to maintain any extra table where I track relations or column names. The only limitation in my application design is, I have to utilize a certain naming convention for the constraints. But the countervalue for this is almost no maintenance is required to keep the data consistent and have good performance.
In order to use all above, some constrains needs to be disabled - even permanently.
I [almost] never disable constraints during the normal operation of the application. The point of the constraints is to preserve data quality.
Now, during maintenance, I can disable them temporarily while adding or removing massive amounts of data. Once they data is loaded I make sure they are enabled again before restarting the application.

How to know when to create a composite constraint?

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.

Proper foreign keys for MS SQL Server 2005 without UNIQUE constraints?

I have two tables (MS SQL Server 2005) with an existing application (no DB alterations other than indexes, etc are allowed).
The two tables are:
ActivityDetails (Primary table)
ActivityDetailkey (Primary key)
SubActivities (Child table)
ActivityDetailKey (Refers to ActivityDetails)
Now, there are no contraints on SubActivities for the ActivityDetailKey. Basically, for EACH ActivityDetail row, there can be MANY SubActivities rows and there is nothing stopping the user from deleting an ActivityDetails row and leaving the SubActivities orphaned.
There was supposed to be some "soft locks" in the application that would prevent this but it isn't working and I wanted to put some better integrity in the DB layer too.
But I can't seem to add the foreign key because the SubActivities's ActivityDetailKey column isn't UNIQUE.
How can I prevent people from deleting the ActivityDetails rows if there are children present?
Thanks
EDIT
I apologize for the complexity. The SubActivities table is actually named TEDetailSubActivities. I changed it in the question so that it would be easier to read.
But anyway, here is a gist of the complete schema for both tables.
https://gist.github.com/840479
I appreciate any help.
It sounds like you're trying to set up your foreign key the wrong way around - if there are multiple rows in SubActivities with the same ActivityDetailKey value, and these are references to the primary key in ActivityDetails, then the following should work (based on your posted schema, and now tested):
ALTER TABLE TEDetailSubActivities ADD CONSTRAINT FK_TEDetailSubActivities_ActivityDetails FOREIGN KEY
(ActivityDetailKey) references dbo.ActivityDetails (ActivityDetailKey)
previous version, based on table names in post:
ALTER TABLE SubActivities ADD CONSTRAINT FK_SubActivities_ActivityDetails FOREIGN KEY
(ActivityDetailKey) references ActivityDetails (ActivityDetailKey)
There's no uniqueness requirement on the ActivityDetailKey column in SubActivities.
As-is, that'll stop deletion of rows from ActivityDetails if there are rows in SubActivities that reference them. If, on the other hand, you want the application to be able to continue with its deletes, but avoid leaving orphaned rows in SubActivities, add ON DELETE CASCADE after the final closing bracket above.
The above works based on the following table definitions. If it doesn't work in your database, you need to help us out by posting either the actual table definitions from your database, or something "close enough" for us to mimic what you're seeing:
create table ActivityDetails (
ActivityDetailkey int not null Primary key
)
go
create table SubActivities (
ActivityDetailKey int not null
)
go
Sigh. If you're going to insist on using the SSMS designers:
Right click on SubActivities, choose "Design".
Press the "Relationships" toolbar button
Press "Add"
Press "..." against the "Tables and Columns Specification" property
In the "Primary key table" drop down, choose "ActivityDetails"
In the grid below, choose ActivityDetailKey on both sides
Press "OK", "Close", the "Save" toolbar button, and (if necessary) "Yes" to the save warning
Close the Designer.
You can have a foreign key, even if its duplicated on the child table, you should add the constraint WITH CHECK option, for example:
ALTER TABLE [dbo].[SubActivities] WITH CHECK ADD CONSTRAINT [FK_SubActivities_ActivityDetails] FOREIGN KEY([ActivityDetailkey])
REFERENCES [dbo].[ActivityDetails ] ([ActivityDetailkey])
Hope it helps!

How do I rename primary key values in Oracle?

Our application uses an Oracle 10g database where several primary keys are exposed to the end user. Productcodes and such. Unfortunately it's to late to do anything with this, as there are tons of reports and custom scripts out there that we do not have control over. We can't redefine the primary keys or mess up the database structure.
Now some customer want to change some of the primary key values. What they initially wanted to call P23A1 should now be called CAT23MOD1 (not a real example, but you get my meaning.)
Is there an easy way to do this? I would prefer a script of some sort, that could be parametrized to fit other tables and keys, but external tools would be acceptable if no other way exists.
The problem is presumably with the foreign keys that reference the PK. You must define the foreign keys as "deferrable initially immediate", as described in this Tom Kyte article: http://www.oracle.com/technology/oramag/oracle/03-nov/o63asktom.html
That lets you ...
Defer the constraints
Modify the parent value
Modify the child values
Commit the change
Simple.
Oops. A little googling makes it appear that, inexplicably, Oracle does not implement ON UPDATE CASCADE, only ON DELETE CASCADE. To find workarounds google ORACLE ON UPDATE CASCADE. Here's a link on Creating A Cascade Update Set of Tables in Oracle.
Original answer:
If I understand correctly, you want to change the values of data in primary key columns, not the actual constraint names of the keys themselves.
If this is true it can most easily be accomplished redefining ALL the foreign keys that reference the affected primary key constraint as ON UPDATE CASCADE. This means that when you make a change to the primary key value, the engine will automatically update all related values in foreign key tables.
Be aware that if this results in a lot of changes it could be prohibitively expensive in a production system.
If you have to do this on a live system with no DDL changes to the tables involved, then I think your only option is to (for each value of the PK that needs to be changed):
Insert into the parent table a copy of the row with the PK value replaced
For each child table, update the FK value to the new PK value
Delete the parent table row with the old PK value
If you have a list of parent tables and the PK values to be renamed, it shouldn't be too hard to write a procedure that does this - the information in USER_CONSTRAINTS can be used to get the FK-related tables for a given parent table.

How do I clear a table with a lot of references in oracle?

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.