SQL Server constraints on foreign keys - sql-server

I have an ItemComments table that has one column with a foreign key constraint linking back to an item entry in a second table. I see this as a one-to-many relationship as each item in the second table can have many comments, but no two items can be associated with the same comment entry in the ItemComments table, so a many-to-many relationship does not apply.
PROBLEM:
I want to define a constraint on this column that will prevent the foreign key value from being updated, i.e. I want to prevent someone from accidentally changing the item ID that a specific ItemComment entry is associated with. I'm not very familiar with the expression formatting of constraint check and was curious what the syntax would be for such an action. Or is there another more straightforward way of accomplishing this? Thanks for the help.
UPDATE
Is it better to implement a cross-reference table as you would in a many-to-many relationship to enforce referential integrity in this way? Or is that adding more overhead than is necessary?

You can always use a trigger. Something like:
create trigger dml_PreventUpdate
on YourTable
after update
as
if UPDATE(ItemId)
rollback
There's two types of Data Manipulation Language (DML) triggers. There's an INSTEAD OF and then an AFTER/FOR trigger (AFTER and FOR function the same way). An INSTEAD OF trigger, as the name implies, executes prior to the transaction taking place. An AFTER trigger, again as the name implies, executes after the triggered action.
Basically all this trigger is doing is testing to see if the ItemId column is updated from the UPDATE statement run against the table, YourTable. This trigger will fire every time there is an UPDATE against YourTable, but it will only ROLLBACK the transaction if ItemId is an updated field.

Related

Trigger to delete column only if all values are null

How can I create a Trigger that delete a column only if all values on a specific field are null?
What do you mean "create a trigger"? Do you mean that you want an update/delete trigger that would delete the column at the point when all the values become NULL?
If so, that is not possible. "Deleting a column" is really alter table drop column. In the Remarks section for the create trigger documentation:
Additionally, the following Transact-SQL statements are not allowed
inside the body of a DML trigger when it is used against the table or
view that is the target of the triggering action . . .
ALTER TABLE when used to do the following: Add, modify, or drop columns. Switch partitions. Add or drop PRIMARY KEY or UNIQUE
constraints.
Hence what you want to do is not possible. Further, I don't understand why you would want to do it. A data-driven change to the data structure seems strange. I am guessing that your data structure really wants to be a junction/association table, but you don't provide enough information to speculate further.

SQL Server Foreign Key cause cycles or multiple cascade paths

I'm having problems adding a cascade delete onto a foreign key in SQL Server. Table A has three columns. Column 1 and 2 in Table A are foreign key look ups to the same column in Table B. I want a delete of a row in Table B to cascade a delete on a row on Table A based on these foreign keys.
The other column in Table A has a foreign key lookup to table C. If a row in table C is deleted then I want the corresponding cell to be set to null in Table A.
When I add in these constraints I am thrown the error:
Introducing FOREIGN KEY constraint 'FK_RDU_TODELIVERABLEUNITREF' on table 'RelatedDeliverableUnit' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I am a little stuck with this, Oracle seems perfectly happy with this logic. I am adding in these constraints using Liquibase. I think the error is down to my logic and not syntax but for completeness here is the liquidbase script that manages the foreign keys:
<addForeignKeyConstraint constraintName="FK_RDU_FROMDELIVERABLEUNITREF" baseTableName="relatedDeliverableUnit"
baseColumnNames="FROMDELIVERABLEUNITREF" referencedTableName="DELIVERABLEUNIT" referencedColumnNames="DELIVERABLEUNITREF" onDelete="CASCADE"/>
<addForeignKeyConstraint constraintName="FK_RDU_TODELIVERABLEUNITREF" baseTableName="relatedDeliverableUnit"
baseColumnNames="TODELIVERABLEUNITREF" referencedTableName="DELIVERABLEUNIT" referencedColumnNames="DELIVERABLEUNITREF" onDelete="CASCADE"/>
<addForeignKeyConstraint constraintName="FK_RDU_RELATIONSHIPREF"
baseTableName="relatedDeliverableUnit" baseColumnNames="RELATIONSHIPREF" referencedTableName="RELATIONSHIPTYPES" referencedColumnNames="RELATIONSHIPREF" onDelete="SET NULL"/>
Thanks in advance for any help
I can't find corresponding documentation for later versions, but the SQL Server 2000 BOL addresses this issue:
The series of cascading referential actions triggered by a single DELETE or UPDATE must form a tree containing no circular references. No table can appear more than once in the list of all cascading referential actions that result from the DELETE or UPDATE. The tree of cascading referential actions must not have more than one path to any given table. Any branch of the tree is terminated when it encounters a table for which NO ACTION has been specified or is the default.
And later versions haven't changed this. You're falling foul of this:
The tree of cascading referential actions must not have more than one path to any given table
The only way I know of to accomplish this is to implement one of the cascades between B and A using an INSTEAD OF trigger, rather than using ON DELETE....
The relation between tables A and C shouldn't be impacted by any of this.
(2008 BOL)

how to create sql server trigger and call it in mvc3 model

I have four tables ie.
custAddress
custCompany
custContact and
custInfo
All of the table has 'cId' field common.
I have a interface in MVC3 view from which I will take inputs for all field except 'cId'. When I take input from the interface all of the above tables must be filled.
Also when I delete data, once I delete data from one table all the data from the other three table should be deleted.
I don't know how to use trigger for this. Please explain how can I do this using trigger or any other way. Any help is appreciated.
To me it sounds more like a database design problem. You do not need trigger here. Keep one of your table as primary (may be CustInfo) and have other table dependent(foreign key relationships) on this. Use cascade delete constraints on dependent tables. When you delete data from CustInfo, cascade delete constraint will take care of deleting corresponding data from dependent tables.

Cascade Delete Use Case

I am pretty new to Business Analysis. I have to write requirements that show both (for now) cascade delete (for two tables) and the rest of the tables will delete explicitly.
I need some guidance for how to write the requirements for cascade deletion.
Delete child entities on parent
deletion.
Delete collection members if collection entity is deleted.
Actually it is hard to understand the task without context and also it smells like university/colledge homework (we had one very similar to this).
Use the ON DELETE CASCADE option to specify whether you want rows deleted in a child table when corresponding rows are deleted in the parent table. If you do not specify cascading deletes, the default behavior of the database server prevents you from deleting data in a table if other tables reference it.
If you specify this option, later when you delete a row in the parent table, the database server also deletes any rows associated with that row (foreign keys) in a child table. The principal advantage to the cascading-deletes feature is that it allows you to reduce the quantity of SQL statements you need to perform delete actions.
For example, the all_candy table contains the candy_num column as a primary key. The hard_candy table refers to the candy_num column as a foreign key. The following CREATE TABLE statement creates the hard_candy table with the cascading-delete option on the foreign key:
CREATE TABLE all_candy
(candy_num SERIAL PRIMARY KEY,
candy_maker CHAR(25));
CREATE TABLE hard_candy
(candy_num INT,
candy_flavor CHAR(20),
FOREIGN KEY (candy_num) REFERENCES all_candy
ON DELETE CASCADE)
Because ON DELETE CASCADE is specified for the dependent table, when a row of the all_candy table is deleted, the corresponding rows of the hard_candy table are also deleted. For information about syntax restrictions and locking implications when you delete rows from tables that have cascading deletes, see Considerations When Tables Have Cascading Deletes.
Source: http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.sqls.doc/sqls292.htm
You don't write use cases for functionality - that is the reason why it is hard to properly answer your question - we don't know the actor who interacts with the system and of course we know nothing about the system, so we cannot tell you how to write description of their interactions.
You should write your use cases first and from them derive the functionality.

Conflicting triggers in Oracle database

I have two tables as follows:
department(alpha, college, etc.)
course(id, alpha, college, title, etc.)
College and alpha are present in both tables by design. I decided to de-normalize a little because the college and alpha are always desired when viewing a course.
I have one trigger that executes after the department table is updated so that it updates all rows in the course table with the new alpha and college values. I also have a trigger that executes before updating the course table to make sure that the alpha-college pair that the user submitted in his or her edits exists in the department table; if the pair isn't there it raises and application error.
These triggers conflict. The second one checks that the new values for the department table are in their, but they aren't yet so it fails like it should.
Is it possible to ignore the second trigger if the first trigger is executed first? I really don't want to execute the second trigger in this case, since I know the values are in the first table. If that's not possible, is there a better way to do this without changing my schema?
Your second trigger sounds like nothing more than a foreign key. Drop it and create a foreign key constraint on course instead. That works in my tests.
However, it seems like unnecessary work to support a denormalization that provides little benefit. If you just want to write simple queries, create a view that joins the two tables and use that in your queries. If you are concerned about the join performance, I doubt very much that it will be a problem, unless you are missing obvious indexes on the tables.
I would sincerely recommend removing your trigger approach all together since it's burdened by dirty reads. Whenever I faced a challenge such as this I would implement the DML using Stored Procedures only. You get all the advantages of triggers without the headaches if implemented properly.
If your fear is you want to make sure all updates to the department table follow your logic as do changes in course, remove update permissions to any user except the owner of the stored procedure. This ensures the only caller who can modify that table is the stored procedure you control and understand. And by coincidence, it becomes the only way to update the tables.
Just $0.02
Like most other cases implemented with triggers, you can see the burden here because the data-model itself has defects.
You can implement the same logic as below and maintain all rules using PK and FK constraints.
---Department references College...
Create table department(
department_id number primary key,
aplha varchar2(20) not null,
college varchar2(20) not null
);
***--Course belongs to a department.. so should be a child of department.
--If it's possible for different depts to give the same course (IT and CS),
--you'll have
--a dept_course_asc table***
Create table Course(
course_id number primary key
department_id number references department(department_id),
course_name varchar2(100) not null
);
if you have a student table, you'll associate it with the course table with another student_table association table.
It might appear these are a lot more tables than you intially showed, but if you want to avoid data redundancies and don't want to have the burden of updating columns in all tables whenever they change in the parent table, the above model is the only way to go.
There are two possible solutions to the problem.
Solution 1: Using DEFERRABLE FK constraint.
This solution is only possible if (alpha, college) combination is unique and can be defined as a PK for department table.
In this case, you do not need the trigger on the course table.
Instead, you define a DEFERRABLE FK (alpha, college) on course that referenced the department table.
And before the update on department you must execute SET CONSTRAINT ... DEFERRED statement see documentation.
Then the FK will be not verified until the commit.
Solution 2: Using system context
You switch off the second trigger using the local system_context.
The context must be created first. see User Created Contexts
The trigger on department set a variable in the context to a some value.
And in the second trigger on courses you check the value of the variable in the context

Resources