【问题标题】:Generic DELETE UPDATE with TRY CATCH使用 TRY CATCH 的通用删除更新
【发布时间】:2011-11-02 23:49:37
【问题描述】:

我正在尝试使用通用参数运行此过程。

如果我因为某些外键而无法删除,它应该更新该行。

但是当我执行它时,仍然永远运行并且没有完成该过程,有什么想法吗?

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER procedure [dbo].[stp_Batch_Registros_Desativados_Excluir]
    @table_name VARCHAR(100),   
    @id          int
AS
BEGIN 
        DECLARE @column VARCHAR(100),
                @sql    VARCHAR(300);

       SET @column = (SELECT COLUMN_NAME 
                      FROM INFORMATION_SCHEMA.COLUMNS 
                        WHERE COLUMNPROPERTY(OBJECT_ID(TABLE_NAME),COLUMN_NAME,'IsIdentity') = 1 
                        AND TABLE_NAME = @table_name);


    BEGIN TRY    
         select @sql = 'DELETE ' + @table_name + ' WHERE ' + @column + ' = ' + CONVERT(VARCHAR,@id);     
         exec(@sql);    
    END TRY

    BEGIN CATCH
        select @sql = 'UPDATE ' + @table_name + ' SET fg_excluido = 2 WHERE ' + @column + ' = ' + CONVERT(VARCHAR,@id) ;
        exec(@sql);
    END CATCH;
END

【问题讨论】:

  • 不能在 T-SQL 语句中为表名或列名使用参数 - 除非先将语句创建为字符串,然后“执行”该字符串(动态SQL - 在尝试使用动态 SQL 之前,您必须阅读The Curse and Blessing of Dynamic SQL!)
  • 我觉得有必要指出潜在的 SQL 注入...
  • 你们在这里过激。表名是一个参数,他正在构建一个执行的 sql 语句。我认为这不是问题。
  • @marcio,你有没有运行 sql profiler 来查看它的锁定位置?是在删除还是更新?桌上是否有可能影响事物的触发器?

标签: sql-server-2008 sql-delete


【解决方案1】:

这对我来说似乎很好用。你有触发器、级联外键等吗?

USE tempdb;
GO
CREATE TABLE dbo.fooblat1
(
    id INT IDENTITY(1,1) PRIMARY KEY,
    x VARCHAR(1),
    fg_excluido TINYINT NOT NULL DEFAULT 1
);

CREATE TABLE dbo.fooblat2
(
    blatid INT NOT NULL FOREIGN KEY REFERENCES dbo.fooblat1(id)
);

INSERT dbo.fooblat1(x) SELECT 'a';
INSERT dbo.fooblat2 SELECT SCOPE_IDENTITY();
INSERT dbo.fooblat1(x) SELECT 'b';
GO

然后:

CREATE PROCEDURE [dbo].[proc]
    @table_name VARCHAR(100),   
    @id         INT
AS
BEGIN 
    SET NOCOUNT ON;

    DECLARE @column NVARCHAR(100),
            @sql    NVARCHAR(MAX);

    SELECT @column = name
        FROM sys.columns
        WHERE [object_id] = OBJECT_ID(@table_name)
        AND is_identity = 1;

    BEGIN TRY    
        SET @sql = 'DELETE [' + @table_name 
            + '] WHERE [' + @column + '] = ' 
            + CONVERT(VARCHAR(12),@id);     

        EXEC sp_executesql @sql;    
    END TRY
    BEGIN CATCH
        SET @sql = 'UPDATE [' + @table_name 
            + '] SET fg_excluido = 2 WHERE ' 
            + @column + ' = ' + CONVERT(VARCHAR(12),@id);

        EXEC sp_executesql @sql;
    END CATCH;
END
GO

然后:

EXEC [dbo].[proc] 'fooblat1', 1; -- should update
GO
EXEC [dbo].[proc] 'fooblat1', 2; -- should delete
GO
SELECT * FROM dbo.fooblat1;
GO

清理:

DROP PROC [dbo].[proc];
DROP TABLE dbo.fooblat2;
DROP TABLE dbo.fooblat1;
GO

【讨论】:

  • 那么,您是否查看了桌面上是否有触发器?您是否验证了外键是否是使用 ON CASCADE 操作创建的?您是否检查过sys.dm_exec_requests 以查看请求正在等待什么或是否被阻止?
  • 我在这张表上有我的主键,它是其他人的外键。我没有任何触发器
  • 那么你是说你运行了我提供的代码(在 tempdb 中)而且它也“永远运行”?
  • 是的,我只是将@sql 声明更改为nvarchar。
  • 抱歉,还没关注。你是运行了我的代码,还是对你的代码做了一些小的调整?哪个代码永远运行,你的代码还是我的代码,或者两者兼而有之?而当它永远运行时,你有没有看sys.dm_exec_requests
猜你喜欢
  • 1970-01-01
  • 2013-03-09
  • 2011-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多