【问题标题】:Stored procedure that needs to handle multiple scenarios需要处理多种场景的存储过程
【发布时间】:2020-10-24 23:22:18
【问题描述】:

我有一个相当复杂(至少对我而言)的存储过程要编写,它需要处理来自前端的多个场景。

前端正在传递 2 个具有类似值的参数

@Levelmarker= (1234515-564546-65454,4654342-154658-56767,5465489-546549-65456)

这些是用逗号分隔的 GUID。

@`UserNameId= (5797823-65432143-65451213)

在前端输入此数据的用户的 GUID

值需要转到具有以下结构的表:

CREATE TABLE LevelTable 
(
    LevelId uniqueidentifier NOT NULL
    LevelMarker uniqueidentiriet NOT NULL
    UserName uniqueidentifier NOT NULL
);

我希望值像这样进入表格:

LevelId    Levelmarker              UserName
--------------------------------------------------------
NEWID()    1234515-564546-65454     5797823-654321-65451 
NEWID()    4654342-154658-56767     5797823-654321-65451
NEWID()    5465489-546549-65456     5797823-654321-65451 

这里是存储过程应该处理的场景。

  1. 一旦levelmarkers被插入到表中,如果同一个用户回来并想要添加额外的Levelmarkers,前端将传递旧值和新值:(1234515-564546-65454,4654342-154658-56767,5465489-546549-65456,1332245-9852135-7841265)

    我的存储过程应该识别出我已经在表中拥有前三个Levelmarkers,并且应该只插入新的。

  2. 如果同一个用户决定删除之前的值,比如说两个值,前端会将值 (1234515-564546-65454,4654342-154658-56767) 传递给我。存储过程应该识别出用户删除了两个值,应该从表中删除相同的值并保留未删除的值。

  3. 如果用户删除一些值并插入新值,则存储过程应识别要删除的值并插入新值。

解决这个问题的最佳方法是什么?

【问题讨论】:

  • 我建议您认真重新考虑一种方法,其中一个过程在调用该过程的过程中没有非常明确的指示插入或删除行。 Erland 讨论了这种 csv 方法 here 和更现代的方法 here。 FWIW - 名为 UserName 的列在逻辑上与 GUID 数据类型不匹配。这种不匹配会增加混乱并使您的系统更难理解。
  • 您最好使用表值参数传递单个 guid,而不是传递然后连接然后拆分它们。

标签: sql-server string stored-procedures sql-insert sql-delete


【解决方案1】:

认为您可以在单个查询中执行此操作,使用 string_split()merge 语句:

merge leveltable t
using (
    select value levelmarker, @UserNameId username
    from string_split(@LeveMarker, ',')
) s
on (s.levelmarker = t.levelmarker and s.username = t.username)
when not matched by target  
    then insert (leveid,    levelmarker,   username) 
         values (newid(), s.levelmarker, s.username)
when not matched by source 
    then delete

using 子句中,我们将@LevelMarker 参数拆分为新行,并关联给定的@UserNameId。然后,merge 语句检查目标表中是否已存在每个组合,并相应地创建或删除行。

【讨论】:

  • 这样一个简单而优雅的解决方案。谢谢@GMB!它适用于所有场景。我看到的唯一问题是,当我在测试存储过程时为两个参数传递空值时,它删除了 LevelTable 中的所有值。有没有办法防止这种情况发生?
  • @DDLearn:可能只是using 子句中的where 子句? where value is not null and @userNameId is not null.
猜你喜欢
  • 2015-05-13
  • 1970-01-01
  • 1970-01-01
  • 2019-12-19
  • 1970-01-01
  • 2013-07-14
  • 2019-10-28
  • 2015-05-13
  • 1970-01-01
相关资源
最近更新 更多