實現刪除主表數據時, 判斷與之關聯的外鍵表是否有數據引用, 有標誌, 無則刪除

 

問題描述:

某個基礎信息表,與系統中30多個表存在外鍵關係,當刪除基礎數據時,需要判斷是否已經被用過,如果用過則更改標誌位,如果沒有用過則直接刪除,如何能很好實現這個處理?最好能夠自動適應表的變化

 

問題解決(SQL Server 2005

-- SQL Server 2005的錯誤處理容易控制, 因此, SQL Server 2005可以直接刪除, 通過錯誤處理來確定是否需要更新.

 

-- 示例如下.

USE tempdb

GO

 

CREATE TABLE m(

    id int PRIMARY KEY,

    bz bit)

INSERT m SELECT 1, 0

UNION ALL SELECT 2, 0

 

CREATE TABLE c(

    id int primary key,

    a_id int references m(id)

        ON DELETE NO ACTION)

INSERT c SELECT 1, 1

GO

 

-- 刪除處理存儲過程

CREATE PROC dbo.p_delete

    @id int

AS

SET NOCOUNT ON

BEGIN TRY

BEGIN TRAN

    DELETE FROM m WHERE id = @id

COMMIT TRAN

END TRY

BEGIN CATCH

    ROLLBACK TRAN

    IF ERROR_NUMBER() = 547 -- 如果是外鍵約束錯誤

    BEGIN

        BEGIN TRY

        BEGIN TRAN          -- 更新標誌

            UPDATE m SET bz = 1

            WHERE id = @id

        COMMIT TRAN

        END TRY

        BEGIN CATCH

            SELECT ERROR_NUMBER(), ERROR_MESSAGE()

        END CATCH

    END

    ELSE

        SELECT ERROR_NUMBER(), ERROR_MESSAGE()

END CATCH

GO

 

-- 調用

EXEC dbo.p_delete 1

EXEC dbo.p_delete 2

SELECT * FROM m

SELECT * FROM c

GO

 

DROP TABLE c, m

DROP PROC dbo.p_delete

 

問題解決(SQL Server 2000

-- SQL Server 2000 對錯誤處理不好控制, 一般還是建議做判斷

-- 通過系統表查詢系統表,可以獲取某個表關聯的所有外鍵表

 

-- 示例存儲過程

CREATE PROC dbo.p_Delete

    @tbname sysname,        -- 基礎數據表名

    @PkFieldName sysname,   -- 基礎數據表關鍵字段名

    @PkValue int            -- 要刪除的基礎數據表關鍵字值

AS

SET NOCOUNT ON

DECLARE @bz bit, @s nvarchar(4000)

DECLARE tb CURSOR LOCAL

FOR

SELECT N'

SET @bz = CASE WHEN EXISTS(

        SELECT * FROM ' + QUOTENAME(@tbname)

        + N' A, ' + QUOTENAME(OBJECT_NAME(B.fkeyid))

        + N' B

        WHERE A.' + QUOTENAME((SELECT name FROM syscolumns WHERE colid = B.rkey AND id = B.rkeyid))

        + N' = B.' + QUOTENAME((SELECT name FROM syscolumns WHERE colid = B.fkey AND id = B.fkeyid))

        + N' AND A.' + QUOTENAME((SELECT name FROM syscolumns WHERE colid = B.rkey AND id = B.rkeyid))

        + N' = @id) THEN 1 ELSE 0 END'

FROM sysobjects A

    JOIN sysforeignkeys B

        ON A.id=  B.constid

    JOIN sysobjects C

        ON A.parent_obj = C.id

WHERE A.xtype = 'f'

    AND C.xtype = 'U'

    AND OBJECT_NAME(B.rkeyid) = @tbname

OPEN tb

FETCH tb INTO @s

WHILE @@FETCH_STATUS = 0

BEGIN

    EXEC sp_executesql @s, N'@tbname sysname, @id int, @bz bit OUT', @tbname, @PkValue, @bz OUT

    IF @bz = 1

    BEGIN

        SET @s = N'UPDATE ' + QUOTENAME(@tbname)

            + N' SET bz = 1 WHERE ' + QUOTENAME(@PkFieldName)

            + N' = @id'

        EXEC sp_executesql @s, N'@id int', @PkValue

 

        RETURN

    END

 

    FETCH tb INTO @s

END

CLOSE tb

DEALLOCATE tb

 

SET @s = N'DELETE FROM ' + QUOTENAME(@tbname)

    + N' WHERE ' + QUOTENAME(@PkFieldName)

    + N' = @id'

EXEC sp_executesql @s, N'@id int', @PkValue

GO

 

注意事項

設置表的主/外鍵關係的時候,不要設置級聯刪除(ON DELETE CASCADE

發佈了34 篇原創文章 · 獲贊 0 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章