In out DB we have a table called "AGENCY" with AGENCY_ID as primary key (PK). There are also about 30 tables that use AGENCY_ID as a foreign key (FK) which references PK in "AGENCY" table.
Is there a way to count how many times a specific PK value AGENCY_ID (i.e. 1004) is referenced as FK in all of the 30 "referencing" tables without checking each individual linked table.
Referential Integrity exception gets thrown when you try to delete row with PK referenced in another table, so I assume there must be a way to check if references in other tables exist.
I tried looking at all_constraints and all_tab_columns tables, but they do not solve the problem. Any ideas how to solve it? Thanks
I don't think any data dictionary view is available for achieving your goal but you should need to create procedure or function to achieve this goal. Without this you cannot get result of PK value AGENCY_ID (i.e. 1004) referenced or not if referenced then how many times.
Related
I am getting the ORA-2270 error when I try to create some Oracle tables.
The error is quite simple from what I have read so far:
It happens when the columns I reference in the foreign key do not
match a primary key or unique constraint on the parent table.
The problem is that my tables have several foreign keys, and I am trying to reference a PK column on a materialized view (because I do not have the chance of getting access to the real table, only the MV).
How can I then create my tables and reference them to the correct PKs in the materialized view given that MVs does not have PKs?
And generally talking... What is the common procedure once this problem occurs?
Thanks in advance.
I have a SQL Server database and it contains a table to record a employee salary.
It has 3 columns declared as foreign keys, and reference to the employee table's column, employee_id:
employee_id
submitted_by
confirmed_by
But is it best practice to make it all as FK, or do I only need employee_id?
Because in my application, submitted_by and confirmed_by will be selected by a drop down list and assume it exist on employee table.
Thanks you for advice.
Yes, since all users of your system are also Employees modelled by your system, if you wish to have Referential Integrity (RI) enforced in the database, all three columns should have foreign keys back to the referenced employee table. Note that since confirmed by sounds like part of a workflow process, where the user confirming may not be available at the time the record is inserted, you can make the field confirmed_by in table EmployeeSalary nullable (confirmed_by INT NULL), in which case RI will only be enforced at the later time when the field is actually populated.
You should name each of the foreign keys appropriately by expressing the role in the foreign key, e.g.
FK_EmployeeSalary_SalariedEmployee
FK_EmployeeSalary_EmployeeSubmittedBy
FK_EmployeeSalary_EmployeeConfirmedBy
Although the front end may restrict choices via the drop down, referential integrity is still beneficial:
Protect against bugs, e.g. where the submitted by employee is omitted (in the case of a non-nullable FK) or the employee provided doesn't exist in the employees table.
Prevent accidental deletion of an employee to which foreign key data is linked.
There is a (very) minor performance penalty on RI whereby the DB will need to check the existence of the PK in the employee table - in most instances this will be negligible.
Any column that references a key in another table should be declared as a foreign key. This way, if you mistakenly try to put a nonexistent value there, the database will report an error.
I found a case in ER where for the life of me I can't figure out how to achieve referential integrity. The classical Employee, Manager, Department relationship can illustrate this problem.
With the following constraints:
Employee can work in only one Department.
Department can have many Employees.
Employee can have one Manager working in the same Department.
Manager can have many Employees working in the same Department.
Employee that doesn't have a Manager is a Manager.
This diagram illustrates the concept.
Before normalisation I end up with the following table.
After normalisation I end up with these tables.
However, there is still nothing stopping me from accidentally assigning a manager working in one department to an employee working in a different department in the EmployeeManager table.
One possible solution that I found was to put Department into the EmployeeManager table and define a reference integrity constraint so that {Manager, Department} refers {Employee, Department} in the EmployeeDepartment table.
However, for this to work doesn't {Manager, Department} have to be a candidate key? Is there a different design that can solve this?
Update
Ok to answer my first question, doesn't {Manager, Department} have to be a candidate key? It turns out that the {Manager, Department} in the EmployeeManager table doesn't have to be a candidate key or a unique key. It simply has to be a foreign key referencing the {Employee, Department} in the EmployeeDepartment table. The uniqueness of {Employee, Department} key isn't well defined and may differ between different engines. MySQL for example advises that the foreign keys reference only unique keys.
Additionally, MySQL requires that the referenced columns be indexed for performance reasons. However, the system does not enforce a requirement that the referenced columns be UNIQUE or be declared NOT NULL. The handling of foreign key references to nonunique keys or keys that contain NULL values is not well defined for operations such as UPDATE or DELETE CASCADE. You are advised to use foreign keys that reference only UNIQUE (including PRIMARY) and NOT NULL keys.
In my case it will work because Employee can only work in one Department however if the constraint chances to allow Employees work in many Departments it won't work because {Employee, Department} will no longer be unique.
It should work in all cases including if the constraint chances to allow Employees work in many Departments.
Is there a different design that can solve this? I also thought about replacing EmployeeDepartment with ManagerDepartment table with {Manager} as a primary key and going back to a previous EmployeeManager table with (Employee, Manager) columns. So now to find out which Department an Employee works you need to join EmployeeManager with ManagerDepartment table.
Do you see any bad practises or anomalies with this design?
Assuming all these columns are declared NOT NULL . . .
One possible solution that I found was to put Department into the
EmployeeManager table and define a reference integrity constraint so
that {Manager, Department} refers {Employee, Department} in the
EmployeeDepartment table.
Yes, add a column for "department" to the "EmployeeManager" table. But you need two foreign key constraints that overlap. (But see below . . .)
(manager, department) references EmployeeDepartment (Employee, Department)
(employee, department) references EmployeeDepartment (Employee, Department)
Since EmployeeDepartment.Employee is unique, the pair of columns EmployeeDepartment.Employee and EmployeeDepartment.Department is also unique. So you can declare "Employee" as a primary key, and also declare a unique constraint on the pair of columns (Employee, Department). Should the requirements change and allow employees to work in multiple departments, you can drop the single-column primary key. I would probably drop both the primary key and unique constraints, and create a new primary key constraint that included both columns, but all that's strictly necessary is to drop the primary key constraint.
In systems like yours, it's usually a good idea to have a table of managers, with the obvious foreign key references. Right now, if you delete the employee Will, you lose the fact that Steve is a manager.
I have got two questions when designing a database for a sales system.
Is it possible to have a isolated table, which means a table does not have relationship with all other tables?
How to solve the following issue:
Table: SalesOrderDetail, Table: InventoryTrans
Every record in SalesOrderDetail will insert into InventoryTrans, but not all records in InventoryTrans are from SalesOrderDetail. Because other tables may also insert records into the InventoryTrans.
Therefore, I want to add a reference column SalesOrderDetailID to InventoryTrans table, but does not specify FK constraint. Because if the record is not from SalesOrderDetail table, then the SalesOrderDetailID should be null.
Is this the right design?
Yes, you can have a table that has no foreign key references to other tables. A table that stores various configuration settings is probably the most common, but there are others.
The column InventoryTrans.SalesOrderDetailID can be a nullable foreign key reference. But you haven't provided enough detail to tell whether that's a good design decision. Making an educated guess, I'd say probably not. (Other kinds of transactions would probably benefit from a foreign key reference.)
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