I have table1, table2 and table3 with lets say ID as a common column (no referential integrity is defined but its maintained programmatically with Table1 considered to be the Primary) .
I also have another common column EmpSalary in all the three tables. My requirement is to auto update all the three tables with EmpSalary when anyone of the tables is updated. Is there anything in SQL server which allows to add an auto update statement to the other two tables without enforcing cascade rule ?
P.S - I have tried and researched several possible options and am leaning towards triggers now which is not my favorite object to implement. Looking for alternate solutions here to see if I can avoid triggers.
#Lmu92 - client does not want any constraints on the db, so no an option. Triggers is my current solution looking for ideas until end of day
You could either use a trigger or take care of it in your code (e.g. stored procedure).
Or -my preferred solution- add referential integrity (=foreign key constraints) with cascading updates.
But this would require a "master" table holding the EmpSalary values and being the only one that gets updated...
None of the other options worked, so I ended up going with triggers.
Related
Let's say I have a Customers table with columns ID and CompanyId.
I need to delete some companies from the DB.
The problem is, the table has a lot of child tables and those tables also has a lot of child tables and so on...
Just to clarify, all the relationships are with constraints.
How can I accomplish that ?
Thanks.
EDIT: Notice that what i'm trying to do is a one time operation.
Whether i will change the constraints or add triggers or anything like that, I'm planning on removing it in the end.
The inbuilt solution to this problem is to set up your FK constraints with ON DELETE CASCADE.
However many people (myself included) are somewhat uneasy about doing this as a mistaken delete will silently propagate through the database.
Here are three ways:
Use a stored procedure to delete child first then up to the parent row in a transation.
I personally wouldn't make it dynamic and would have a specific "DeleteCompany" proc. Your may need a rule that such as "no delete if sales > 100 million" that needs checked
CASCADE DELETEs on your foreign keys
This can be tricky if you have multiple cascade paths, but simple otherwise
INSTEAD OF trigger
An INSTEAD OF trigger is like a stored procedure in operation. Note: You'll get an FK violation before an AFTER trigger fires
Personally, I'd use a stored proc so I have explicit deletes. The effect is the same as cascading FKs but more obvious.
For SQL Server 2008, this is the solution:
Generate Delete Statement From Foreign Key Relationships in SQL 2008?
With this solution, you can easily find the correct sequence of DELETE respecting, in the meantime, the foreign keys' relationships.
If you are interested in this theme, you can read also the ORACLE PL/SQL solution:
How to generate DELETE statements in PL/SQL, based on the tables FK relations?
This is more of a curiosity at the moment, but let's picture an environment where I bill on a staunch nickle&dime basis. I have many operations that my system does and they're all billable. All these operations are recorded across various tables (these tables need to be separate because they record very different kinds of information). I also want to micro manage my accounts receivables. (Forgive me if you find inconsistencies here, as this example is not a real situation)
Is there a somewhat standard way of substituting a foreign key with something that can verify that the identifier in column X on my billing table is an existing identifier within one of many operations record tables?
One idea is that when journalizing account activity, I could reference the operation's identifier as well as the operation (specifically, the table that it's in) and use a CHECK constraint. This is probably the best way to go so that my journal is not ambiguous.
Are there other ways to solve this problem, de-facto or proprietary?
Do non-relational databases solve this problem?
EDIT:
To rephrase my initial question,
Is there a somewhat standard way of substituting a foreign key with something that can verify that the identifier in column X on my billing table is an existing identifier within one of many (but not necessarily all) operations record tables?
No, there's no way to achieve this with a single foreign key column.
You can do basically one of two things:
in your table which potentially references any of the other x tables, have x foreign key reference fields (ideally: ID's of type INT), only one of which will ever be non-NULL at any given time. Each FK reference key references exactly one of your other data tables
or:
have one "child" table per master table with a proper and enforced reference, and pull together the data from those n child tables into a view (instead of a table) for your reporting / billing.
Or just totally forget about referential integrity - which I would definitely not recommend!
you can Implementing Table inheritance
see article
http://www.sqlteam.com/article/implementing-table-inheritance-in-sql-server
An alternative is to enforce complex referential integrity rules via a trigger. However,and not knowing exactly what your design is, usually when these types of questions are asked it is to work around a bad design. Look at the design first and see if you can change it to make this something that can be handled through FKs, they are much more managable than doing this sort of thing through triggers.
If you do go the trigger route, don't forget to enforce updates as well as inserts and make sure your trigger will work properly with a set-based multi-row insert and update.
A design alternative is to havea amaster table that is parent to all your tables with the differnt details and use the FK against that.
I have two databases in SQL Server and i have a common table for both the databases an important big table which holds the foreign keys to other tables. The problem is the Table is in DatabaseA, and I need to refer foreign keys to this table from DatabaseB.
I know SQL doesn't support cross database referential integrity so what's the best way to achieve this? I am thinking of combining two databases and make into single database - it wouldn't matter aside from the increase in complexity.
Any suggestions?
I would avoid doing this if I could - can you just keep both tables in one datbase and use an FK?
Parent and Child Tables Are in Different Databases.
Although you cannot use a foreign key in this situation, there are workarounds – you can use either triggers or UDFs wrapped in check constraints. Either way, your data integrity is not completely watertight: if the database with your parent table crashes and you restore it from a backup, you may easily end up with orphans.
Parent-Child Relationship Is Enforced by Triggers.
There are quite a few situations when triggers do not fire, such as:
· A table is dropped.
· A table is truncated.
· Settings for nested and/or recursive triggers prevent a trigger from firing.
Also a trigger may be just incorrect. Either way, you may end up with orphans in your database.
Here's an article on how to use the SSIS Import / Export wizard:
http://www.databasejournal.com/features/mssql/article.php/3580216/SQL-Server-2005-Import--Export-Wizard.htm
The easiest way to do this is just to export one database (I'd use the smallest of the two) to whatever format is the most convenient for you, and then import it into the other. As long as the table names are all different, this shouldn't present any problem.
Triggers can be written to enforce referential integrity against different databases.
I have an Access 2003 app that connects to a SQL Server 2000 box.
I have a table in which I need to lock down a record along with all related records in different tables. By "lock down", I mean mark them as read-only so that no clients can edit those records unless an admin unlocks them.
Any ideas?
More than likely there isn't an "elegant" way of doing this at the database level. But there are a few routes you could do.
Add a "locked" bit field to each table, and when "locking" the parent cascade that value.
In conjunction with #1 add a trigger on update and delete, if the flag is set, you can cancel the update or delete.
That is about the only real easy way to enforce it at the db level that I can think of.
Assuming your data is in SQL Server, I would use the SQL Server security if possible first. We typically would not allow any access to tables and then control it through SPs. SPs can have more complex logic to determine whether a particular operation should go through.
If that's not an option, you can always use triggers, check the rows and deny an update or delete that way.
There's a ton of ways to skin this cat.
Just another option to throw out there:
Add a last_updated column to your
table, which is updated by the update
trigger
Create a table, Locked_Widgets (or whatever) which is simply the PK of your base table and the last_updated column and the whole set of columns make up the PK in Locked_Widgets
Put a non-cascading foreign key from the base table to Locked_Widgets
If anyone tries to update the row the trigger will try to update the last_updated column and the foreign key constraint will cause the update to fail.
Can anyone provide a clear explanation / example of what these functions do, and when it's appropriate to use them?
Straight from the manual...
We know that the foreign keys disallow creation of orders that do not relate to any products. But what if a product is removed after an order is created that references it? SQL allows you to handle that as well. Intuitively, we have a few options:
Disallow deleting a referenced product
Delete the orders as well
Something else?
CREATE TABLE order_items (
product_no integer REFERENCES products ON DELETE RESTRICT,
order_id integer REFERENCES orders ON DELETE CASCADE,
quantity integer,
PRIMARY KEY (product_no, order_id)
);
Restricting and cascading deletes are the two most common options. RESTRICT prevents deletion of a referenced row. NO ACTION means that if any referencing rows still exist when the constraint is checked, an error is raised; this is the default behavior if you do not specify anything. (The essential difference between these two choices is that NO ACTION allows the check to be deferred until later in the transaction, whereas RESTRICT does not.) CASCADE specifies that when a referenced row is deleted, row(s) referencing it should be automatically deleted as well. There are two other options: SET NULL and SET DEFAULT. These cause the referencing columns to be set to nulls or default values, respectively, when the referenced row is deleted. Note that these do not excuse you from observing any constraints. For example, if an action specifies SET DEFAULT but the default value would not satisfy the foreign key, the operation will fail.
Analogous to ON DELETE there is also ON UPDATE which is invoked when a referenced column is changed (updated). The possible actions are the same.
edit: You might want to take a look at this related question: When/Why to use Cascading in SQL Server?. The concepts behind the question/answers are the same.
I have a PostGreSQL database and I use On Delete when I have a user that I delete from the database and I need to delete it's information from other table. This ways I need to do only 1 delete and FK that has ON delete will delete information from other table.
You can do the same with ON Update. If you update the table and the field have a FK with On Update, if a change is made on the FK you will be noticed on the FK table.
What Daok says is true... it can be rather convenient. On the other hand, having things happen automagically in the database can be a real problem, especially when it comes to eliminating data. It's possible that in the future someone will count on the fact that FKs usually prevent deletion of parents when there are children and not realize that your use of On Delete Cascade not only doesn't prevent deletion, it makes huge amounts of data in dozens of other tables go away thanks to a waterfall of cascading deletes.
#Arthur's comment.
The more frequently "hidden" things happen in the database the less likely it becomes that anyone will ever have a good handle on what is going on. Triggers (and this is essentially a trigger) can cause my simple action of deleting a row, to have wide ranging consequences throughout my database. I issue a Delete statement and 17 tables are affected with cascades of triggers and constraints and none of this is immediately apparent to the issuer of the command. OTOH, If I place the deletion of the parent and all its children in a procedure then it is very easy and clear for anyone to see EXACTLY what is going to happen when I issue the command.
It has absolutely nothing to do with how well I design a database. It has everything to do with the operational issues introduced by triggers.
Instead of writing the method to do all the work, of the cascade delete or cascade update, you could simply write a warning message instead. A lot easier than reinventing the wheel, and it makes it clear to the client (and new developers picking up the code)