我有以下内容:
文件可以包含其他文件(视频文件包含音频和字幕),一般情况下,内容文件不会单独保存,只会显示为主文件的一部分。但是在某些特殊情况下,我将一些内容文件分开保存。
我也有商店,所以如果是主文件,那么一个文件在商店中,如果我有一个辅助文件也保存在主文件中。
所以我有两个表:
如果我想删除主文件,我只想从特定的sotre中删除,所以如果文件在其他商店中,我不想删除该文件。如果文件不在另一个商店,我想删除该文件,因为在数据库中包含这些信息是没有意义的。
另外,我想删除所有内容文件,只有当内容文件没有单独存储在主文件之外的其他商店中时。
为了确保我不能删除其他商店中的文件,我不会在级联上删除StoresHasFiles上的关系,所以这样我得到了一个外国人密钥错误。
所以我想按照这个步骤:
我想我需要一个交易才能做到这一点,但我不知道该怎么做。
我不知道是否可以使用我要删除的文件声明列表,如何迭代此列表以及如何尝试删除内容文件,以及是否因某些内容文件无法删除存储在另一个地方,尝试删除下一个内容文件。
也许还有其他方法可以解决这个问题?
感谢。
答案 0 :(得分:2)
有几种不同的方法可以做到这一点。关于事务,了解语法和用法的最简单方法是在MSDN上阅读Begin Transaction。
对于删除,我的方式是:
-- Assumed inputs
DECLARE @StoreId int;
DECLARE @FileIdToDelete int;
-- Query
SET XACT_ABORT ON; -- Forces whole transaction to roll back if
-- there was an error at any point
BEGIN TRAN;
DECLARE @NumberOfStoresContainingFile int;
-- Find out how many stores have this file
SELECT @NumberOfStoresContainingFile = COUNT(*)
FROM StoresHaveFiles shf
WHERE IDFile = @FileIdToDelete
-- If it is more than one we know we dont want to delete so signal caller
IF (@NumberOfStoresContainingFile > 1)
RAISERROR(<addYourDetailsHere>);
-- Remove any contained files of the main file we want to remove
DELETE f
FROM Files f
WHERE EXISTS (SELECT *
FROM FilesContainsFiles fcf
WHERE fcf.IDContainerFile = @FileIdToDelete AND fcf.IDContentFile = f.IDFile);
-- Remove the main file entry itself
DELETE
FROM Files
WHERE IDFile = @FileIdToDelete;
-- Remove the JOIN table record between store and file
DELETE StoresHaveFiles
WHERE IDStore = @StoreId
AND IDFile = @FileIdToDelete;
-- This is an optimistic approach (it assumes the file belongs to the store you asked about
-- if the file is only in one store). This check is to ensure that the JOIN record was
-- deleted. If it is not, this means the file did not belong to the store and an error
-- should be thrown. To do this pessimistically, simply do this check before the deletes
-- and after the count check.
IF (@@rowcount = 0)
RAISERROR(<addYourDetailsHere>);
COMMIT;
答案 1 :(得分:1)
我会通过一系列检查来解决这个问题。
如果文件存在于指定的商店..否则什么都不做。 如果该文件存在于其他商店......否则只需从一个商店中删除。
例如:
IF OBJECT_ID('TEMPDB..#Files') IS NOT NULL DROP TABLE #Files
IF OBJECT_ID('TEMPDB..#FilesContainsFiles') IS NOT NULL DROP TABLE #FilesContainsFiles
IF OBJECT_ID('TEMPDB..#Stores') IS NOT NULL DROP TABLE #Stores
IF OBJECT_ID('TEMPDB..#StoresHaveFiles') IS NOT NULL DROP TABLE #StoresHaveFiles
CREATE TABLE #Files ([IDFile] INT IDENTITY(1,1), [FileName] VARCHAR(100))
CREATE TABLE #FilesContainsFiles ([IDContainerFile] INT, [IDContentFile] INT)
CREATE TABLE #Stores ([IDStore] INT IDENTITY(1,1), [StoreName] VARCHAR(100))
CREATE TABLE #StoresHaveFiles ([IDStore] INT, [IDFile] INT)
INSERT INTO #Stores (StoreName) VALUES ('Target'),('Walmart')
INSERT INTO #Files ([FileName]) VALUES ('true.blood.mkv'), ('game.of.thrones.mkv'), ('game.of.thrones-swe.sub')
INSERT INTO #FilesContainsFiles (IDContainerFile, IDContentFile) VALUES (2,3)
INSERT INTO #StoresHaveFiles (IDStore, IDFile) VALUES (1,1),(1,2),(2,2)
DECLARE @StoreToDeleteFrom VARCHAR(100), @FileToDelete VARCHAR(100)
--SET @StoreToDeleteFrom='Target'
SET @StoreToDeleteFrom='Walmart'
--SET @FileToDelete='true.blood.mkv'
SET @FileToDelete='game.of.thrones.mkv'
SELECT *
FROM #Files F
LEFT OUTER JOIN #FilesContainsFiles FParent ON F.IDFile=FParent.IDContainerFile
LEFT OUTER JOIN #StoresHaveFiles SHF ON F.IDFile=SHF.IDFile
LEFT OUTER JOIN #Stores S ON SHF.IDStore=S.IDStore
-- IF THE FILE IS AT OUR STORE...
IF EXISTS (SELECT *
FROM #Files F
LEFT OUTER JOIN #StoresHaveFiles SHF ON F.IDFile=SHF.IDFile
LEFT OUTER JOIN #Stores S ON SHF.IDStore=S.IDStore
WHERE S.StoreName=@StoreToDeleteFrom
AND F.[FileName]=@FileToDelete)
BEGIN
-- IF THE FILE IS NOT AT ANY OTHER STORE
IF NOT EXISTS (SELECT *
FROM #Files F
LEFT OUTER JOIN #StoresHaveFiles SHF ON F.IDFile=SHF.IDFile
LEFT OUTER JOIN #Stores S ON SHF.IDStore=S.IDStore
WHERE S.StoreName<>@StoreToDeleteFrom
AND F.[FileName]=@FileToDelete)
BEGIN
-- GO AHEAD AND DELETE FILE EVERYWHERE...
PRINT 'DELETE FILE'
DELETE SHF
FROM #Stores S
JOIN #StoresHaveFiles SHF
ON S.IDStore=SHF.IDStore
JOIN #Files F
ON SHF.IDFile=F.IDFile
AND F.[FileName]=@FileToDelete
WHERE S.StoreName=@StoreToDeleteFrom
DELETE FCF
FROM #Files F
JOIN #FilesContainsFiles FCF
ON F.IDFile=FCF.IDContentFile
WHERE F.[FileName]=@FileToDelete
DELETE FCF
FROM #Files F
JOIN #FilesContainsFiles FCF
ON F.IDFile=FCF.IDContainerFile
WHERE F.[FileName]=@FileToDelete
DELETE F
FROM #Files F
WHERE [FileName]=@FileToDelete
END
ELSE
BEGIN
-- ONLY DELETE FROM STORE
PRINT 'DELETE FILE FROM STORE ONLY'
DELETE SHF
FROM #Stores S
JOIN #StoresHaveFiles SHF
ON S.IDStore=SHF.IDStore
JOIN #Files F
ON SHF.IDFile=F.IDFile
AND F.[FileName]=@FileToDelete
WHERE S.StoreName=@StoreToDeleteFrom
END
END
ELSE
BEGIN
-- ITS NOT AT THAT STORE...
PRINT 'NOTHING TO DELETE'
END
SELECT *
FROM #Files F
LEFT OUTER JOIN #FilesContainsFiles FParent ON F.IDFile=FParent.IDContainerFile
LEFT OUTER JOIN #StoresHaveFiles SHF ON F.IDFile=SHF.IDFile
LEFT OUTER JOIN #Stores S ON SHF.IDStore=S.IDStore