【问题标题】:SQL Server stored procedures for INSERT and UPDATE, better to separate or condense?用于 INSERT 和 UPDATE 的 SQL Server 存储过程,最好分开还是压缩?
【发布时间】:2011-07-28 19:41:35
【问题描述】:

我正在创建用于在我的 SQL Server 数据库中插入和更新数据的存储过程。起初我正在为 Add/Set 创建一个单独的过程,但后来我偶然发现了一个查询,该查询允许我将它们压缩为一个过程。我想与 SO 社区核实以这种方式进行的任何可能的未来问题。

单独的程序

--INSERT Procedure
CREATE PROCEDURE [dbo].[AddDataType]
    @TypeName [nvarchar](255),
    @TypeProperty [nvarchar](255)
AS
BEGIN
    SET NOCOUNT ON;

    INSERT INTO DataType(TypeName, TypeProperty)
    VALUES(@TypeName, @TypeProperty)

    SELECT SCOPE_IDENTITY()
END

--UPDATE Procedure
CREATE PROCEDURE [dbo].[SetDataType]
    @ID [int],
    @TypeName [nvarchar](255),
    @TypeProperty [nvarchar](255)
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE DataType SET TypeName = @TypeName, TypeProperty = @TypeProperty
    WHERE ID = @ID
 END

EXEC AddDataType @TypeName = 'Test Name', @TypeProperty = 'Test Property' --INSERT
EXEC SetDataType @ID = 42, @TypeName = 'Test Name', @TestProperty = 'Test Property' --UPDATE

合并

CREATE PROCEDURE [dbo].[SetDataType]
    @ID [int] = NULL,
    @TypeName [nvarchar](255),
    @TypeProperty [nvarchar](255)
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE DataType SET TypeName = @TypeName, TypeProperty = @TypeProperty
    WHERE ID = @ID

    IF @@ROWCOUNT = 0
        INSERT INTO DataType(TypeName, TypeProperty)
        VALUES(@TypeName, @TypeProperty)

    IF @ID IS NULL
        SELECT SCOPE_IDENTITY()
END

EXEC SetDataType @TypeName = 'New Type Name', @TypeProperty = 'New Type Property' --INSERT
EXEC SetDataType @ID = 42, @TypeName = 'Updated Type Name', @TypeProperty = 'Updated Type Property' --UPDATE

到目前为止,我有 15 个类型表,我为它们创建了过程,并试图减少创建的过程的数量,但是我不想牺牲性能。我知道第二种方法需要更多处理,但它是否足以引起问题?我没有看到存储大量数据的类型表,不超过 100 条记录,平均在 10-20 条左右。

感谢任何想法或建议。

【问题讨论】:

  • 我个人更喜欢有单独的、有重点的程序——我不喜欢那些做各种事情的“全部做然后再做一些”的方法——这一切都取决于什么你传入的值....
  • @marc_s 我对搜索过程没意见,即使对于各种参数 (DRY),大部分逻辑都没有改变。在 MERGE 之前(除非应用程序可能不知道此项目是新项目还是现有项目),对于 DML,我通常同意您的看法。
  • 如果不存在,您将在尝试更新时进行扫描。问题是真的,你想要有好的 SQL 性能还是更少的 procs?

标签: sql-server sql-server-2008 stored-procedures


【解决方案1】:

什么版本的 SQL Server?这些信息总是有用的,所以请养成用特定版本标记问题的习惯。

如果 或更高版本,您可能会考虑使用MERGE 而不是单独的INSERT/UPDATE 操作,但自从写下这个答案后,我肯定改变了自己的态度,更喜欢您提出的UPDATE / IF @@ROWCOUNT = 0 / INSERT 方法。有关详细信息,请参阅:

这是一个MERGE 示例(在 tempdb 中运行它),但我再次建议不要使用它。

CREATE TABLE dbo.DataType
(
    ID             int IDENTITY(1,1),
    TypeName       nvarchar(255),
    [TypeProperty] nvarchar(255),
    CONSTRAINT PK_DataType PRIMARY KEY (ID)
);

INSERT dbo.DataType(TypeName, [TypeProperty]) VALUES (N'name 1', N'property 1');
GO

然后是一个程序:

CREATE PROCEDURE dbo.MergeDataType
    @ID           int = NULL,
    @TypeName     nvarchar(255),
    @TypeProperty nvarchar(255)
AS
BEGIN
    SET NOCOUNT ON;

    WITH [source](ID, TypeName, [TypeProperty]) AS 
    (
        SELECT @ID, @TypeName, @TypeProperty
    )
    MERGE dbo.DataType WITH (HOLDLOCK) AS [target] 
      USING [source] ON [target].ID = [source].ID
    WHEN MATCHED THEN
        UPDATE SET [target].TypeName       = @TypeName,
                   [target].[TypeProperty] = @TypeProperty
    WHEN NOT MATCHED THEN
        INSERT (TypeName, [TypeProperty]) 
        VALUES (@TypeName, @TypeProperty);
END
GO

现在让我们运行它并检查结果:

EXEC dbo.MergeDataType 
    @TypeName     = N'foo', 
    @TypeProperty = N'bar';

EXEC dbo.MergeDataType 
    @ID           = 1, 
    @TypeName     = N'name 1', 
    @TypeProperty = N'new property';
GO

SELECT ID, TypeName, [TypeProperty] FROM dbo.DataType;
GO

清理:

DROP TABLE dbo.DataType;
DROP PROCEDURE dbo.MergeDataType;

【讨论】:

  • 抱歉重新标记。现在是 08,我不知道 MERGE 功能。我会试一试。谢谢
  • 如果 MERGE 由于某种原因对您不起作用,那么我会提倡单独的过程路径 - 特别是如果应用程序预先知道这是添加还是编辑,特别是如果存储的以后程序可能会变得更复杂(因此将受益于单独的编译计划)。
  • 到目前为止,我在 MERGE 函数上找到的所有内容都是在两个表之间引用合并数据(INSERT/UPDATE/DELETE)。就我而言,这将是对单个表的直接调用。基本上我想要根据它是否存在来插入/更新。您能否提供一个使用 MERGE 的示例,还是我应该坚持单独的程序?
  • “两张表”不一定是实际的物理表。他们只需要闻起来像它。
  • 编辑你的问题,看看你是怎么做这些时髦标签的
【解决方案2】:
USE [//Your Database Name]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[InsertIcone] 
    -- Add the parameters for the stored procedure here
(
@amount decimal(18,0),
@payer  nvarchar(50),
@paymentMode  nvarchar(50),
@date date,
@description nvarchar(Max),
@operatorId int
)
AS
begin
if exists (select *  from wallet2 as t where payer=@payer)
begin
    update wallet2 set amount=@amount,payer=@payer,paymentMode=@paymentMode,
    [date]=@date,[description]=@description where id=(select id  from 
    wallet2 as t where payer=@payer) and operatorId=@operatorId
end
else 
begin
         insert into dbo.Wallet2 
         values(@amount,@payer,@paymentMode,@date,@description,@operatorId);
    end

END

【讨论】:

  • 这应该是上述问题的答案吗?至少你应该解释你的代码(并请格式化它)
猜你喜欢
  • 2011-01-15
  • 2012-08-08
  • 1970-01-01
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
  • 2018-05-04
  • 1970-01-01
  • 2011-02-21
相关资源
最近更新 更多