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

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.

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.

deleting in tables in a specific order

Hy,my question is how can i use a procedure in which i can delete data from one table and then from the other to avoid the problem with the REFERENTIAL INTEGRITY, I tried it like this
create procedure usp_Testovi_Delete
(
#TestoviID int
)
as
delete from Testovi
where TestoviID=#TestoviID
delete from RezultatiTesta
where TestoviID=#TestoviID
but I need to execute it twice to delete data from both tables , ty for your time and help , I'm using SQL server.
There are a variety of ways to handle this:
Delete from the table with the foreign key first.
Wrap the first delete in a blank exception handler, then delete from the second table, and finally delete from the first table again.
Disable the foreign keys while you perform the delete, and re-enable them afterward.
They each have advantages and disadvantages :-/

SQL Foreign Key in Another Database

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;

Disable DELETE for a table in SQL Server

I'm currently working on creating a table for customers in an order management system for a course at university. The system relies on being able to retrieve order histories for the customers. Since we've chosen not to store these in a separate table, removing the option to delete rows from our customer table is essential.
How and where do I set this up in the CREATE statement? I suspect I'll have to create a rule about what should happen instead, but I'm not entirely sure about the specifics.
On SQL Server, you have the following options:
Deny object permissions. For example: DENY DELETE ON OBJECT::dbo.Customer TO db_datawriter;
Raise an error in a trigger: CREATE TRIGGER nodelete1 ON dbo.Customer INSTEAD OF DELETE AS RAISERROR('You can't delete from this table', 16, 10)
Rely on referential integrity without cascading updates/deletes. Note that this will only prevent deletion of a customer, if the customer has at least 1 order.
In my honest opinion, however, I think that this should be solved at the application level and not the database level. Even if using the techniques above, what would prevent someone from simply removing the trigger or grant the necessary permissions before DELETE'ing the records? Or simply dropping the entire table?
If you don't want your users to delete records from a table, simply make sure that your application does not allow them to do that. Anyone working directly with the database should know that issuing a DELETE statement could be dangerous - especially if you don't have a backup.
If the table is accessed only through an application, you can use a soft delete, to do that add a column to the table, for example IsDeleted, and check it in the software to see whether the row is live or deleted.
If the final users can access the DB, you can to change his/her login or group permission to remove the delete grant on that table.
i do it with a simple trigger on each table that i want disable delete
Create Trigger [dbo].[RollBackDelete]
ON [dbo].[Your Table Name]
INSTEAD OF DELETE
AS
BEGIN
ROLLBACK;
END
ofcourse if you have any key with cascade operation on delete or update it can not be work and you should set it to "No Action"
i hope this be be useful

SQL - How can I temporarily protect the data in this table?

I am populating a table that acts as a cache. (This is needed because the data comes through a linked server and joins through the link are too expensive)
I've included pseudo code below that hopefully demonstrates what I'm trying to do. I really don't know if there's a way to lock a table down like this, or if I need to use transactions, but here's the basics:
Delete everything in the CacheTable
Populate the cacheTable
Process the data in CacheTable for 10 seconds (it's important that other instances of this stored procedure don't delete the CacheTable during processing!)
Return the processed results (CacheTable is free again)
delete from CacheTable -- If this errors because it is locked, exit stored procedure
[[Lock CacheTable]]
insert into CacheTable
exec RemoteDB.dbo.[sp_GrabRecords] #Start, #End, #Key
Process Cached Data
...
Select Processed Data
[[Unlock CacheTable]]
How can I protect the data in this CacheTable while it is being processed?
Note: I'm also looking for alternatives. I tried using a table variable, but it was too slow, probably because it didn't have a primary key. Not even sure if tables variables can have primary keys. I just know the method above is extremely fast, but it has a problem with collisions, obviously
isn't that CacheTable a temporary table, so each instance of the stored procedure should allocated it's own; thus avoiding the locking problem
Add a GUID (uniqueidentifier) column to your cache table. Have each executing instance of the stored procedure create a new GUID (NEWID()) to uniquely identify it's rows in the cached table. That way you do not need to lock out other running instances.
When done, delete the rows that match your GUID only.