【问题标题】:TSQL add or delete rows inside procedure based on selectionTSQL根据选择在过程中添加或删除行
【发布时间】:2012-11-11 03:27:08
【问题描述】:

我有一个拥有用户访问权限的表:

  Id  |  UserId  |  SectionId
  ---------------------------
  1   |  1       |  1
  2   |  1       |  2
  3   |  2       |  1
  4   |  1       |  3

使用此代码:

CREATE FUNCTION dbo.Split (@List    NVARCHAR(2000), 
                       @SplitOn NVARCHAR(5)) 
returns @RtnValue TABLE ( 
   id    INT IDENTITY(1, 1), 
   value NVARCHAR(100)) 
AS 
BEGIN 
  WHILE ( Charindex(@SplitOn, @List) > 0 ) 
    BEGIN 
        INSERT INTO @RtnValue 
                    (value) 
        SELECT Value = Ltrim(Rtrim(Substring(@List, 1, Charindex(@SplitOn, 
                                                       @List) 
                                                       - 1))) 

        SET @List = Substring(@List, Charindex(@SplitOn, @List) + Len( 
                                     @SplitOn 
                                     ), 
                    Len 
                    (@List)) 
    END 

  INSERT INTO @RtnValue 
              (value) 
  SELECT Value = Ltrim(Rtrim(@List)) 

  RETURN 
END 

我创建了一个返回的函数(现在是特定用户和部分的所有记录):

CREATE PROCEDURE UpdateSettings(@UserId int, @NewSettings nvarchar(255))
AS
BEGIN
  SELECT * 
  FROM settings
  WHERE 
    UserId = @UserId AND 
    SectionId IN (SELECT convert(int,Value) FROM dbo.Split(@NewSettings,','))
END;

这可以在http://sqlfiddle.com/#!3/79de7/4进行测试

我想修改此过程,以便删除存在的项目并添加不存在的新项目。

这是一个例子。我想改变这个:

  Id  |  UserId  |  SectionId
  ---------------------------
  1   |  1       |  1
  2   |  1       |  2
  3   |  2       |  1
  4   |  1       |  3

进入:

  Id  |  UserId  |  SectionId
  ---------------------------
  1   |  1       |  1
  3   |  2       |  1
  4   |  1       |  3
  5   |  1       |  4

这应该通过调用来完成:

EXEC UpdateSettings @UserId=1, @NewSettings='2,4'

因为有 UserId=1 和 SectionId=2 的行应该删除它,因为 userId=1 和 SectionId=4 行不存在我想创建它。

我的第一个想法是为 NewSettings 创建一个游标,然后检查该行是否存在,如果存在则删除它,如果不存在则添加它。

第二个想法是像这样删除所有已经存在的行:

CREATE PROCEDURE UpdateSettings(@UserId int, @NewSettings nvarchar(255))
AS
BEGIN
  DELETE 
  FROM settings
  WHERE 
    UserId = @UserId AND 
    SectionId IN (SELECT convert(int,Value) FROM dbo.Split(@NewSettings,','))
  END;

这样我就可以删除已经存在的记录,但不知道如何添加新记录(就像在我的示例中,我必须删除表中存在的一行并添加一个新记录)

我想避免使用光标,也许会做某种 JOIN,但我不知道如何做到这一点。

【问题讨论】:

    标签: sql tsql sql-server-2005


    【解决方案1】:

    如果我这样做,我会保持简单:

    1. 删除用户的所有现有数据
    2. 为用户插入所有新数据

    好处是:

    • 易于编码
    • 简单易懂
    • 您希望实现的优化可能太小了,不值得费心

    【讨论】:

    • 是的,我知道这将是最简单的方法。我的程序是从asp页面调用的。我有一个带有复选框的非常大的表,为了最大限度地减少请求,我只将更改发送到服务器。如果我有 1000 个复选框(只是一个示例)并且用户只更改一个并单击保存按钮,我只想更新该设置 - 删除该行或添加新记录。我认为这比删除 1000 行并添加 1000 行要好。
    【解决方案2】:

    在 SQL Server2005 中

    CREATE PROCEDURE UpdateSettings(@UserId int, @NewSettings nvarchar(255))
    AS
    BEGIN
      DECLARE @tmp TABLE(UserId int, SectionId int)
      DELETE s
      OUTPUT DELETED.UserId, DELETED.SectionId INTO @tmp
      FROM settings s JOIN (
                            SELECT @UserId AS UserId, CONVERT(int, Value) AS SectionId 
                            FROM dbo.Split(@NewSettings, ',')  
                            ) d ON s.UserId = d.UserId AND s.SectionId = d.SectionId 
      INSERT settings(UserId, SectionId)
      SELECT @UserId AS UserId, CONVERT(int,Value) AS SectionId
      FROM dbo.Split(@NewSettings, ',') d LEFT JOIN @tmp t ON CONVERT(int, d.Value) = t.SectionId 
                                          LEFT JOIN settings s ON @UserId = s.UserId AND CONVERT(int, d.Value) = s.SectionId
      WHERE t.UserId IS NULL AND s.UserId IS NULL
    END
    

    在 SQLServer 2008 中

    CREATE PROCEDURE UpdateSettings(@UserId int, @NewSettings nvarchar(255))
    AS
    BEGIN
      MERGE settings AS target
      USING (
             SELECT id, @UserID AS UserId, value AS SectionId 
             FROM dbo.Split(@NewSettings,',')
             ) AS source
      ON (target.UserId = source.UserId AND target.SectionId = source.SectionID)
      WHEN MATCHED
        THEN DELETE
      WHEN NOT MATCHED
        THEN INSERT (
                     UserId,
                     SectionId
                     )
             VALUES (
                     source.UserId,
                     source.SectionId
                     );  
    END
    

    【讨论】:

    • 2008 看起来好多了,可惜我不能使用它...感谢您的重播,我会立即检查:)
    • 我同意你和 MERGE 的力量;)
    猜你喜欢
    • 1970-01-01
    • 2015-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-09
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    相关资源
    最近更新 更多