Error from SQL Server - sql

Hello friends I am getting the following error while making the foreign key
'tbl_course' table saved successfully
'tbl_students' table
- Unable to create relationship 'FK_tbl_students_tbl_course'.
Introducing FOREIGN KEY constraint
'FK_tbl_students_tbl_course' on table
'tbl_students' may cause cycles or
multiple cascade paths. Specify ON
DELETE NO ACTION or ON UPDATE NO
ACTION, or modify other FOREIGN KEY
constraints. Could not create
constraint. See previous errors.
I have the following tables College table, Branch table, Course table and Student table
Course has a foreign key college_id, Branch has a foreign key course_id and I want to make college_id, course_id, branch_id as foreign keys to my Student table but while making course_id and branch_id as foreign key in Student table it generate the error mentioned above...please help me to resolve the above problem.....thanks

According to MS
You receive this error message because in SQL Server, a table cannot appear more than one time in a list of all the cascading referential actions that are started by either a DELETE or an UPDATE statement. For example, the tree of cascading referential actions must only have one path to a particular table on the cascading referential actions tree.
http://support.microsoft.com/kb/321843
Can you live without the cascading deletes? Keep the referential ingegrity but not the referenctial actions (cascades). You could resort to a trigger as a work around if needed.
EDIT:
CREATE TRIGGER [dbo].[tr_College_Delete] ON [dbo].[College]
FOR DELETE
AS
BEGIN
DELETE FROM student
where collegeid in (select collegeid from deleted)
END
not tested.

Why would you add anything but branch_id to the student? From there, you should be able to determine which course the branch belongs to and which college the course belongs to.
If you have
College
College1
College2
College3
Course
Course1, College1
Course2, College1
Course3, College2
Branch
Branch1, Course1
Branch2, Course1
Branch3, Course2
Student
Student1,College3,Course3,Branch1
This is valid from the database standpoint, but makes no sense since the student record should be attached to College1 based on the Branch it's attached to. You know logically that if the student is in a branch with ID Branch1 (or whatever primary key you use, but I use this for illustraion purposes) then they must be in Course1 and College1. By adding the additional information to the Student record, you not only create circular references in the code but put yourself in a position to create a "corrupt" record in the database. Of course you can code around this, but why go to the extra effort when you can simplify the student record to simply (Student1,Branch1) without losing any data?
This is known as database normalization, and it's something that's very important to at least consider when you're building a data model.

Related

Is there a way to restrict foreign keys references to another column putting custom rules on this references?

I have three tables that are all user types of my system: master, unit, and employee.
Basically, all of these tables have a column that refers to user(id) (all these tables have a user row too with general data).
The principal point of this question is the employee table, which has a column called employer_id (who is the employer of this employee) where refers to user(id). My issue is I want to restrict the employer_id foreign key reference only to master xor unit, not to the both, and not to users that are neither master and neither unit. But the fact that the employer_id refers to user(id) allows that any type of user of the system can be an employer of this employee.
Is there a way to restrict foreign keys table references?
Yes, you can create a trigger before insert/update that will check whether exists an employee whose user_id matches the value of employer_id. If such a record exists, then throw an exception. See: https://www.postgresql.org/docs/9.1/plpgsql-trigger.html

If I got many to many relationship data first, how do I insert them to my table?

Say I have a customer table, a product table and an order table to record who buys what, the order table basically has 2 foreign keys, customer_id & product_id.
Now I got the order information first, within in it I can't find the customer information in my local database. As it turns out this is a new customer, whose information will come later from another thread/queue. To make things even worse the customer id I got from the order information is not the same one I used locally. My local customer id is INTEGER PRIMARY KEY (I do record that "true customer id" as another column and set index on it)
So how I do record this order information? I can come up with some clumsy solution, e.g. if I can't find contact info, I insert a record for it first. Later after I get the real information for this customer, I update customer & order table. But I was wondering is there any "standard" way for the situation like this?
Inserting NULL values, and then updating with the real values later, is simple and will work (if you don't have a NOT NULL constraint).
You should use a transaction so that concurrent users don't see the incomplete data.
You could use deferred foreign key constraints:
If a statement modifies the contents of the database such that a deferred foreign key constraint is violated, the violation is not reported immediately. Deferred foreign key constraints are not checked until the transaction tries to COMMIT. For as long as the user has an open transaction, the database is allowed to exist in a state that violates any number of deferred foreign key constraints.
However, deferred foreign key constraints are useful only if you are inserting values that violate the constraint; a NULL value is not considered a FK violation.

Logical Modeling difficulty

I have a task to design a simple database that will store information about restaurants, customers and Categories that each restorant falls in (ex. American,Indian...). The problem is that I am not sure how to model the database having the fact that every customer may have zero or more registered other
customers as friends. Whilst a customer can have many friend connections, for
each friend connection the date must be recorded.
I assume that I have to create another table called Friends that will contain the cust_id,data as attributes.
My tables are:
Restaurants(rest_id,name,address,date_opened,income_cat_id*)
Category(car_id,title,Description)
Customers(cust_id,name,address,DOB,Mobile_number)
Here is my ER Diagram, but as I said I am not sure if the Recursive relation is right for my Customers table:
Yes, you need another table to model the connections, something like:
Connection(cust_id1, cust_id2, connectdate)
Thank you a very much!
Does that mean that I have to have the following constraints in the Connection table?
CONSTRAINT pk_Connections PRIMARY KEY (cust_id1,cust_id2),
CONSTRAINT fk_Customers_Connections_cust_id1 FOREIGN KEY (cust_id1) REFERENCES Customers(cust_id)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT fk_Customers_Connections_cust_id2 FOREIGN KEY (cust_id2) REFERENCES Customers(cust_id)
ON DELETE NO ACTION ON UPDATE NO ACTION);

Apply a not null constraint via a many-to-many relationship?

I need to make sure that every project in my database has a contact person. "projects" and "contacts" have a many-to-many relationship, specified in the table "projects_contacts". Could I create a table constraint within projects that will specify the project must exist within the join table? Or do I need to take a completely different approach?
(I need users to be able to manually enter contact data while in the middle of adding project data, so I'm worried that the NOT NULL will hang up their ability to create a project before there is a contact.)
Would this be better addressed in the build of the user interface?
Thanks!
CREATE TABLE projects(
id_project INTEGER PRIMARY KEY,
description text)
CREATE TABLE contacts(
id_contact integer PRIMARY KEY
firstname varchar(100) )
CREATE TABLE projects_contacts(
id_projects_contacts integer PRIMARY KEY,>
id_project integer,
id_contact integer
CONSTRAINT FOREIGN KEY project_fkey (id_project) REFERENCES projects ON UPDATE CASCADE ON DELETE CASCADE
CONSTRAINT FOREIGN KEY contact_fkey (id_contact) REFERENCES contacts ON UPDATE CASCADE ON DELETE CASCADE)
The only way you could implement this with a table-level constraint is for projects to contain a non-nullable foreign key reference to any entry in projects_contacts.
But this would be a circular reference, since projects_contacts also depends on `projects.
You said you don't want to force users to enter a contact while they're still creating a project, so basically you can't constrain a project with a non-nullable reference like that.
There is no constraint that means "I need this to be non-null, but later." It's in the definition of any constraint that it must be satisfied by the time you end the transaction.
Therefore most you can defer a constraint is until commit:
http://www.postgresql.org/docs/9.3/static/sql-set-constraints.html
I assume you will need the deferral to be longer than the length of one transaction.
So ultimately, these types of custom business rules end up being enforced by application code that you have to develop.
If including a contact on the project is mandatory, then your GUI should not send an add request unless the contact data (or key if already exists) is part of the transaction.
This way, you don't need the FK to allow nulls.
However, from business standpoint, what would you do when a contact is no longer a contact for the project and no substitute contact has been assigned?
In this case, your business should make the decision. If so, the FK has to allow nulls on update.
To combine both cases, your FK should allow nulls but your business layer should not accept create project transaction with null contact fk.
You also need to think about this business question: Could a contact exist without a project? The answer is important in your GUI design.
As per your statement "I need users to be able to manually enter contact data while in the middle of adding project data" - This makes sense to me only if the contacts would be directly added to the current project, but what if the user starts creating a project, create a contact then abandons the process of creating the project? How would you identify the added contact? So, may be you want to refine this requirement.

Constrain table entries on sql table

I have 3 related tables as shown in the image below.
Everyone has an entry in the User table and a UserRole.
Some Users are Subscribers.
I want to constrain the Subscribers table so that it can only contain users whose role IsSusbcriber but retain the UserRole at User level. Is it possible?
Excuse the current relationships between the table, they represent whats there at the moment rather whats necessarily needed.
I think you could drop the IsSubscriber columns and add a UserSubscriberRoles table that will contain exactly those roles that had previously set the IsSubscriber column.
CREATE UserSubscriberRoles
( UserRoleId PRIMARY KEY
, FOREIGN KEY (UserRoleId)
REFERENCES UserRoles (UserRoleId)
) ;
Then change the FKs in Subscribers table to:
FOREIGN KEY (UserId, UserRoleId)
REFERENCES User (UserId, UserRoleId)
FOREIGN KEY (UserRoleId)
REFERENCES UserSubscriberRoles (UserRoleId)
Is it possible?
In theory, yes; you can use a SQL assertion. See this StackOverflow answer for an example.
In practice, however, no major DBMS supports SQL assertions, and what you describe cannot be implemented as a foreign-key constraint, so I think your only option is to write a trigger that evaluates this constraint, and raises an exception if it's not satisfied.
The only way to contrain this without RoleId in the table is via either a trigger (and triggers are usually a bad design choice), or a SQL Agent job that periodically removes people from Subscribers that don't fit the criteria.
With RoleID in Subscribers, you can add a check constraint that limits it to a specific value.
This would really be better enforced with a different design and/or in the application code.