SQL Foreign Key in Another Database - sql

I am currently creating a database at work that is essentially a child of another database. When our clients get our software they get a database, lets call it MasterBase. This database contains schema of two different smaller databases put together, lets call them MasterC and MasterF.
My job is to take all the schema that pertain to MasterF and put them in their own database. The problem is there are a lot of references to tables and views in MasterC. To work around this I will add a property that will pair MasterF with MasterC so that in my .NET solution I should be able to do things like:
Table tableName.... (table being created in MasterF)
References .... MasterC.dbo.tableC (table in MasterC)
However, in SQL this raises the error: MSG 1763 Cross-Database foreign key references are not supported.
I have read the most common work around is to add a trigger, but seeings how this is not that safe and there are MANY instances of this I was wondering if there was another way, perhaps a stored procedure or something of the sort.
If a trigger is really the best/only way and I MUST add a trigger to every table that has this problem, how would I go about writing this trigger, I know a little SQL but am hardly proficient.
Please Help!

Triggers (as you mention)...
Database Partitioning...
Duplicate the tables from MasterC (are they transactional? How often are they updated? Does MasterC need the updates? If so, can you allow for the copies to be updated every 24-hours, etc. via a "Job"?)
Per your last comment about individual builds, I guess I'd say that the threshold for when a client "needs" both is when they...well, "need" both. Sounds almost like you need a 3rd schema, for tables in MasterC that do NOT reference MasterF, for those clients you're categorizing as not needing both.
BTW -- this is all about referential integrity, yes? There are other strategies you could employ toward that goal, besides 'relationships'.
EDIT
CREATE TRIGGER myTrigger ON myTable
AFTER INSERT
AS
IF NOT EXISTS (SELECT * FROM OtherDatabase.otherschema.othertable F
JOIN inserted AS i
ON F.KeyYouAreLookingFor = i.KeyYouHave)
BEGIN
RAISERROR ('Lookup Value Not Found -- Insert Failed', 16, 1);
ROLLBACK TRANSACTION;
RETURN
END;

Related

How to delete records of multiple tables in one go? Sqlite

For a project i need to to delete all data from all tables in a database,
I tried
DELETE FROM table1,table2,table3,...;
But it doesnt work. Any advice ? Thank
I would like to refer You to this related post
How do I use cascade delete with SQL Server?
as You will find there several possible solutions.
When using SQL it means that Your data is relations, which means most of the records are somehow related in the different tables and this relation is expressed with foreign keys. However when attempting to delete data which is id is related with data in another table a cascade deletion should be implemented, the other way around it is add additional boolean column named isDeleted(as example ofcourse) and just alter specific rows to true in this specific column and then filter by preferences. Hopefully I have managed somehow to provide with alternative and/or possible solution to Your problem.
Leaving also this link which gives some examples on cascade deletion and guide on how to implement it. ->
https://www.sqlshack.com/delete-cascade-and-update-cascade-in-sql-server-foreign-key/
P.S. also if You want just to DELETE all the data You can either use TRUNCATE TABLE or DROP DATABASE query. With the latest option You will have to recreate the database once more.
Because you want to delete all databases from all tables, you are essentially deleting the database.
The sqlite way of doing this is to just delete the database file.
In contrast to postgres or mongodb or most databases, sqlite doesn't have a server so no need to call DROP DATABASE.
As soon as the file is gone and you open the database from your application you will be in a blank state again.

How to delete items with a many-to-many relationship with 'WHERE' clause in a stored procedure?

In my MSSQL database I have the following three tables:
Tasks
Files
TaskFile
As one can imagine, TaskFile simply maps IDs of the Tasks table to the IDs of the Files table having foreign key constraints to them. I do most of my database operations using stored procedures. Deleting a single file by ID is then easy, I simply have to delete the entries in TaskFile first:
CREATE PROCEDURE [dbo].[spFile_Delete]
#ID INT = 0
AS
BEGIN
DELETE
FROM dbo.[TaskFile]
WHERE FileID = #ID;
DELETE
FROM dbo.[File]
WHERE ID = #ID;
END
However, I'm wondering what the recommended way is to delete multiple files. For example, file entries belong to a dataset and therefore hold a reference to a DatasetID. I have the following procedure to delete by DatasetID however this needs to be adapted to work with the foreign key constraint:
CREATE PROCEDURE [dbo].[spFile_DeleteByDataset]
#DatasetID NVARCHAR(128)
AS
BEGIN
DELETE
FROM dbo.[File]
WHERE DatasetID = #DatasetID;
END
The most straight forward way I can think of, is to first query all the FileIDs with the given DatasetID and then use them to delete all entries in TaskFile first. This should work, but doesn't seem like the best solution, especially if I want to go further and have for example have a stored procedure to delete datasets. Now I would have to:
Find all the files belonging to the dataset
Find all the references in TaskFile and delete dem
Delete all File entries
Delete the dataset entry
and for each relationship this would go further and further and get more and more complicated.
Basically I'm asking for some best practices in such cases. I'm fairly new when it comes to database management and these convolution seem like a good source for errors. Should each stored procedure only handle it's specific table and I have to manage the correct order of entries/updates/deletions in the data access layer code? Is there a way to automate changes with foreign relationships? Or should you simply never delete anything from the database and only have a flag 'deleted' in a separate column?
Oh I believe you are talking about DELETE/UPDATE CASCADE. It's usually not advised because in general you don't want to delete more than you are targeting in the moment. But depending on the scenario it can be used. For example in your case i believe it's ok: if FileTask has ON DELETE CASCADE in the reference to File, when you delete straight the table File, all FileTask related to this file would be deleted together and you wouldn't need to worry about deleting FileTask before. In your case when you want to delete a file, you also want to delete related FileTasks.

Add Foreign Key Contraint between Tables in different Databases [duplicate]

I have two tables in two different databases. In table1 (in database1) there is a column called column1 and it is a primary key. Now in table2 (in database2) there is a column called column2 and I want to add it as a foreign key.
I tried to add it and it gave me the following error:
Msg 1763, Level 16, State 0, Line 1
Cross-database foreign key references are not supported. Foreign key Database2.table2.
Msg 1750, Level 16, State 0, Line 1
Could not create constraint. See previous errors.
How do I do that since the tables are in different databases.
You would need to manage the referential constraint across databases using a Trigger.
Basically you create an insert, update trigger to verify the existence of the Key in the Primary key table. If the key does not exist then revert the insert or update and then handle the exception.
Example:
Create Trigger dbo.MyTableTrigger ON dbo.MyTable, After Insert, Update
As
Begin
If NOT Exists(select PK from OtherDB.dbo.TableName where PK in (Select FK from inserted) BEGIN
-- Handle the Referential Error Here
END
END
Edited: Just to clarify. This is not the best approach with enforcing referential integrity. Ideally you would want both tables in the same db but if that is not possible. Then the above is a potential work around for you.
If you need rock solid integrity, have both tables in one database, and use an FK constraint. If your parent table is in another database, nothing prevents anyone from restoring that parent database from an old backup, and then you have orphans.
This is why FK between databases is not supported.
You could use check constraint with a user defined function to make the check. It is more reliable than a trigger. It can be disabled and reenabled when necessary same as foreign keys and rechecked after a database2 restore.
CREATE FUNCTION dbo.fn_db2_schema2_tb_A
(#column1 INT)
RETURNS BIT
AS
BEGIN
DECLARE #exists bit = 0
IF EXISTS (
SELECT TOP 1 1 FROM DB2.SCHEMA2.tb_A
WHERE COLUMN_KEY_1 = #COLUMN1
) BEGIN
SET #exists = 1
END;
RETURN #exists
END
GO
ALTER TABLE db1.schema1.tb_S
ADD CONSTRAINT CHK_S_key_col1_in_db2_schema2_tb_A
CHECK(dbo.fn_db2_schema2_tb_A(key_col1) = 1)
In my experience, the best way to handle this when the primary authoritative source of information for two tables which are related has to be in two separate databases is to sync a copy of the table from the primary location to the secondary location (using T-SQL or SSIS with appropriate error checking - you cannot truncate and repopulate a table while it has a foreign key reference, so there are a few ways to skin the cat on the table updating).
Then add a traditional FK relationship in the second location to the table which is effectively a read-only copy.
You can use a trigger or scheduled job in the primary location to keep the copy updated.
The short answer is that SQL Server (as of SQL 2008) does not support cross database foreign keys--as the error message states.
While you cannot have declarative referential integrity (the FK), you can reach the same goal using triggers. It's a bit less reliable, because the logic you write may have bugs, but it will get you there just the same.
See the SQL docs # http://msdn.microsoft.com/en-us/library/aa258254%28v=sql.80%29.aspx Which state:
Triggers are often used for enforcing
business rules and data integrity. SQL
Server provides declarative
referential integrity (DRI) through
the table creation statements (ALTER
TABLE and CREATE TABLE); however, DRI
does not provide cross-database
referential integrity. To enforce
referential integrity (rules about the
relationships between the primary and
foreign keys of tables), use primary
and foreign key constraints (the
PRIMARY KEY and FOREIGN KEY keywords
of ALTER TABLE and CREATE TABLE). If
constraints exist on the trigger
table, they are checked after the
INSTEAD OF trigger execution and prior
to the AFTER trigger execution. If the
constraints are violated, the INSTEAD
OF trigger actions are rolled back and
the AFTER trigger is not executed
(fired).
There is also an OK discussion over at SQLTeam - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=31135
Achieving referential integrity accross databases is not an easy task.
Here is a list of frequently employed mechanisms:
Clone & Sync: The referenced data is regularly cloned/merged into the referencing database. This may be suitable if the referenced data is rarely changing. You end up with two physical copies of the same data, and need a reliable process to keep them in sync (e.g. with an ETL pipeline).
Triggers: Changes to the referencing data and the referenced data are caught by SQL triggers, which ensure referential integrity. However, triggers can be slow, and may not fire at a database restore. It cannot hurt to run scheduled consistency checks as part of the operations monitoring. Write access to the referenced database is required for installing and maintaining the trigger.
Check constraints: SQL-Server offers user-defined contraints, which ensure that every row satisfies a given condition. One can exploit this functionality by writing a user defined function that checks the existence of a row in the referenced data, and then use this function as a CHECK's predicate in the referencing table. This does not catch changes in the referenced data. It is an RDBMS-specific solution, but works accross server boundaries (e.g. using linked servers). It is a good choice for referencing globally unique IDs, such as article codes in a company's ERP system, which never get deleted or re-assigned.
Re-think database architecture: When all the above mechanisms are unsatisfactory, multiple databases may be merged in a single database. The originating database names can become schema names, allowing effective grouping of database objects.
As the error message says, this is not supported on sql server.
The only way to ensure refrerential integrity is to work with triggers.

ORACLE After update trigger: solving ORA-04091 mutating table error

I am trying to create a trigger:
create or replace trigger NAME_OF_TRIGGER
after insert or update on table1
REFERENCING OLD AS OLD NEW AS NEW
for each row
to fill in automatically a couple of non obligatory fields when updating/inserting on a table.
This requires me to use a cursor that selects from table2 and also table1 (the subject of the trigger).
Is there any way to avoid the mutating table error without using a temporary table for values or an autonomous transaction?
"Is there any way to avoid the mutating table error without using a
temporary table for values or an autonomous transaction?"
tl;dr no.
The mutating table error is caused by querying the table which owns the trigger, or tables which are involved in a foreign key relationship with the owning table (at least in older versions of the database, not sure whether it still obtains).
In a properly designed application this should not be necessary. This is why many people regard mutating tables as an indicator of poor data modelling. For instance, mutation is often associated with insufficient normalisation.
To paraphrase Jamie Zawinski: Some people, when confronted with a mutating table exception, think "I know, I'll use autonomous transactions." Now they have two problems.
Sometimes the error can be avoided by simply modifying the :NEW values in a BEFORE INSERT OR UPDATE trigger or by using virtual columns. But you'll need to post more details to see whether these apply.
But the best workaround is not to need any other kind.

Add Foreign Key relationship between two Databases

I have two tables in two different databases. In table1 (in database1) there is a column called column1 and it is a primary key. Now in table2 (in database2) there is a column called column2 and I want to add it as a foreign key.
I tried to add it and it gave me the following error:
Msg 1763, Level 16, State 0, Line 1
Cross-database foreign key references are not supported. Foreign key Database2.table2.
Msg 1750, Level 16, State 0, Line 1
Could not create constraint. See previous errors.
How do I do that since the tables are in different databases.
You would need to manage the referential constraint across databases using a Trigger.
Basically you create an insert, update trigger to verify the existence of the Key in the Primary key table. If the key does not exist then revert the insert or update and then handle the exception.
Example:
Create Trigger dbo.MyTableTrigger ON dbo.MyTable, After Insert, Update
As
Begin
If NOT Exists(select PK from OtherDB.dbo.TableName where PK in (Select FK from inserted) BEGIN
-- Handle the Referential Error Here
END
END
Edited: Just to clarify. This is not the best approach with enforcing referential integrity. Ideally you would want both tables in the same db but if that is not possible. Then the above is a potential work around for you.
If you need rock solid integrity, have both tables in one database, and use an FK constraint. If your parent table is in another database, nothing prevents anyone from restoring that parent database from an old backup, and then you have orphans.
This is why FK between databases is not supported.
You could use check constraint with a user defined function to make the check. It is more reliable than a trigger. It can be disabled and reenabled when necessary same as foreign keys and rechecked after a database2 restore.
CREATE FUNCTION dbo.fn_db2_schema2_tb_A
(#column1 INT)
RETURNS BIT
AS
BEGIN
DECLARE #exists bit = 0
IF EXISTS (
SELECT TOP 1 1 FROM DB2.SCHEMA2.tb_A
WHERE COLUMN_KEY_1 = #COLUMN1
) BEGIN
SET #exists = 1
END;
RETURN #exists
END
GO
ALTER TABLE db1.schema1.tb_S
ADD CONSTRAINT CHK_S_key_col1_in_db2_schema2_tb_A
CHECK(dbo.fn_db2_schema2_tb_A(key_col1) = 1)
In my experience, the best way to handle this when the primary authoritative source of information for two tables which are related has to be in two separate databases is to sync a copy of the table from the primary location to the secondary location (using T-SQL or SSIS with appropriate error checking - you cannot truncate and repopulate a table while it has a foreign key reference, so there are a few ways to skin the cat on the table updating).
Then add a traditional FK relationship in the second location to the table which is effectively a read-only copy.
You can use a trigger or scheduled job in the primary location to keep the copy updated.
The short answer is that SQL Server (as of SQL 2008) does not support cross database foreign keys--as the error message states.
While you cannot have declarative referential integrity (the FK), you can reach the same goal using triggers. It's a bit less reliable, because the logic you write may have bugs, but it will get you there just the same.
See the SQL docs # http://msdn.microsoft.com/en-us/library/aa258254%28v=sql.80%29.aspx Which state:
Triggers are often used for enforcing
business rules and data integrity. SQL
Server provides declarative
referential integrity (DRI) through
the table creation statements (ALTER
TABLE and CREATE TABLE); however, DRI
does not provide cross-database
referential integrity. To enforce
referential integrity (rules about the
relationships between the primary and
foreign keys of tables), use primary
and foreign key constraints (the
PRIMARY KEY and FOREIGN KEY keywords
of ALTER TABLE and CREATE TABLE). If
constraints exist on the trigger
table, they are checked after the
INSTEAD OF trigger execution and prior
to the AFTER trigger execution. If the
constraints are violated, the INSTEAD
OF trigger actions are rolled back and
the AFTER trigger is not executed
(fired).
There is also an OK discussion over at SQLTeam - http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=31135
Achieving referential integrity accross databases is not an easy task.
Here is a list of frequently employed mechanisms:
Clone & Sync: The referenced data is regularly cloned/merged into the referencing database. This may be suitable if the referenced data is rarely changing. You end up with two physical copies of the same data, and need a reliable process to keep them in sync (e.g. with an ETL pipeline).
Triggers: Changes to the referencing data and the referenced data are caught by SQL triggers, which ensure referential integrity. However, triggers can be slow, and may not fire at a database restore. It cannot hurt to run scheduled consistency checks as part of the operations monitoring. Write access to the referenced database is required for installing and maintaining the trigger.
Check constraints: SQL-Server offers user-defined contraints, which ensure that every row satisfies a given condition. One can exploit this functionality by writing a user defined function that checks the existence of a row in the referenced data, and then use this function as a CHECK's predicate in the referencing table. This does not catch changes in the referenced data. It is an RDBMS-specific solution, but works accross server boundaries (e.g. using linked servers). It is a good choice for referencing globally unique IDs, such as article codes in a company's ERP system, which never get deleted or re-assigned.
Re-think database architecture: When all the above mechanisms are unsatisfactory, multiple databases may be merged in a single database. The originating database names can become schema names, allowing effective grouping of database objects.
As the error message says, this is not supported on sql server.
The only way to ensure refrerential integrity is to work with triggers.