您的位置:首页 > 数据库 > SQL

实现删除主表数据时, 判断与之关联的外键表是否有数据引用, 有标志, 无则删除

2007-05-11 19:37 561 查看
问题描述:
某个基础信息表,与系统中30多个表存在外键关系,当删除基础数据时,需要判断是否已经被用过,如果用过则更改标志位,如果没有用过则直接删除,如何能很好实现这个处理?最好能够自动适应表的变化

 

问题解决(SQL Server 2005

[align=left]-- SQL Server 2005的错误处理容易控制, 因此,SQL Server 2005中可以直接删除, 通过错误处理来确定是否需要更新.[/align]
[align=left] [/align]
[align=left]-- 示例如下.[/align]
[align=left]USE tempdb[/align]
[align=left]GO[/align]
[align=left] [/align]
[align=left]CREATE TABLE m([/align]
[align=left]    id int PRIMARY KEY, [/align]
[align=left]    bz bit)[/align]
[align=left]INSERT m SELECT 1, 0[/align]
[align=left]UNION ALL SELECT 2, 0[/align]
[align=left] [/align]
[align=left]CREATE TABLE c([/align]
[align=left]    id int primary key, [/align]
[align=left]    a_id int references m(id) [/align]
[align=left]        ON DELETE NO ACTION)[/align]
[align=left]INSERT c SELECT 1, 1[/align]
[align=left]GO[/align]
[align=left] [/align]
[align=left]-- 删除处理存储过程[/align]
[align=left]CREATE PROC dbo.p_delete[/align]
[align=left]    @id int[/align]
[align=left]AS[/align]
[align=left]SET NOCOUNT ON[/align]
[align=left]BEGIN TRY[/align]
[align=left]BEGIN TRAN[/align]
[align=left]    DELETE FROM m WHERE id = @id[/align]
[align=left]COMMIT TRAN[/align]
[align=left]END TRY[/align]
[align=left]BEGIN CATCH [/align]
[align=left]    ROLLBACK TRAN[/align]
[align=left]    IF ERROR_NUMBER() = 547 -- 如果是外键约束错误[/align]
[align=left]    BEGIN[/align]
[align=left]        BEGIN TRY[/align]
[align=left]        BEGIN TRAN          -- 更新标志[/align]
[align=left]            UPDATE m SET bz = 1[/align]
[align=left]            WHERE id = @id[/align]
[align=left]        COMMIT TRAN[/align]
[align=left]        END TRY[/align]
[align=left]        BEGIN CATCH[/align]
[align=left]            SELECT ERROR_NUMBER(), ERROR_MESSAGE()[/align]
[align=left]        END CATCH[/align]
[align=left]    END[/align]
[align=left]    ELSE[/align]
[align=left]        SELECT ERROR_NUMBER(), ERROR_MESSAGE()[/align]
[align=left]END CATCH[/align]
[align=left]GO[/align]
[align=left] [/align]
[align=left]-- 调用[/align]
[align=left]EXEC dbo.p_delete 1[/align]
[align=left]EXEC dbo.p_delete 2[/align]
[align=left]SELECT * FROM m[/align]
[align=left]SELECT * FROM c[/align]
[align=left]GO[/align]
[align=left] [/align]
[align=left]DROP TABLE c, m[/align]
[align=left]DROP PROC dbo.p_delete[/align]

 

问题解决(SQL Server 2000

[align=left]-- SQL Server 2000 对错误处理不好控制, 一般还是建议做判断[/align]
[align=left]-- 通过系统表查询系统表,可以获取某个表关联的所有外键表[/align]
[align=left] [/align]
[align=left]-- 示例存储过程[/align]
[align=left]CREATE PROC dbo.p_Delete[/align]
[align=left]    @tbname sysname,        -- 基础数据表名[/align]
[align=left]    @PkFieldName sysname,   -- 基础数据表关键字段名[/align]
[align=left]    @PkValue int            -- 要删除的基础数据表关键字值[/align]
[align=left]AS[/align]
[align=left]SET NOCOUNT ON[/align]
[align=left]DECLARE @bz bit, @s nvarchar(4000)[/align]
[align=left]DECLARE tb CURSOR LOCAL[/align]
[align=left]FOR[/align]
[align=left]SELECT N'[/align]
[align=left]SET @bz = CASE WHEN EXISTS([/align]
[align=left]        SELECT * FROM ' + QUOTENAME(@tbname) [/align]
[align=left]        + N' A, ' + QUOTENAME(OBJECT_NAME(B.fkeyid))[/align]
[align=left]        + N' B[/align]
[align=left]        WHERE A.' + QUOTENAME((SELECT name FROM syscolumns WHERE colid = B.rkey AND id = B.rkeyid))[/align]
[align=left]        + N' = B.' + QUOTENAME((SELECT name FROM syscolumns WHERE colid = B.fkey AND id = B.fkeyid))[/align]
[align=left]        + N' AND A.' + QUOTENAME((SELECT name FROM syscolumns WHERE colid = B.rkey AND id = B.rkeyid))[/align]
[align=left]        + N' = @id) THEN 1 ELSE 0 END'[/align]
[align=left]FROM sysobjects A[/align]
[align=left]    JOIN sysforeignkeys B[/align]
[align=left]        ON A.id= B.constid[/align]
[align=left]    JOIN sysobjects C [/align]
[align=left]        ON A.parent_obj = C.id[/align]
[align=left]WHERE A.xtype = 'f' [/align]
[align=left]    AND C.xtype = 'U'[/align]
[align=left]    AND OBJECT_NAME(B.rkeyid) = @tbname[/align]
[align=left]OPEN tb[/align]
[align=left]FETCH tb INTO @s[/align]
[align=left]WHILE @@FETCH_STATUS = 0[/align]
[align=left]BEGIN[/align]
[align=left]    EXEC sp_executesql @s, N'@tbname sysname, @id int, @bz bit OUT', @tbname, @PkValue, @bz OUT[/align]
[align=left]    IF @bz = 1[/align]
[align=left]    BEGIN[/align]
[align=left]        SET @s = N'UPDATE ' + QUOTENAME(@tbname) [/align]
[align=left]            + N' SET bz = 1 WHERE ' + QUOTENAME(@PkFieldName)[/align]
[align=left]            + N' = @id'[/align]
[align=left]        EXEC sp_executesql @s, N'@id int', @PkValue[/align]
[align=left] [/align]
[align=left]        RETURN[/align]
[align=left]    END[/align]
[align=left] [/align]
[align=left]    FETCH tb INTO @s[/align]
[align=left]END[/align]
[align=left]CLOSE tb[/align]
[align=left]DEALLOCATE tb[/align]
[align=left] [/align]
[align=left]SET @s = N'DELETE FROM ' + QUOTENAME(@tbname) [/align]
[align=left]    + N' WHERE ' + QUOTENAME(@PkFieldName)[/align]
[align=left]    + N' = @id'[/align]
[align=left]EXEC sp_executesql @s, N'@id int', @PkValue[/align]
[align=left]GO[/align]

 

注意事项

[align=left]设置表的主/外键关系的时候,不要设置级联删除(ON DELETE CASCADE)[/align]

 
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐