【问题标题】:Update database table records based on array of data根据数据数组更新数据库表记录
【发布时间】:2021-09-14 17:56:32
【问题描述】:

我有一个这样的对象数组:

[ {User_ID: 1, Source_ID: 1}, {User_ID: 1, Source_ID: 2}]

还有我的访问表设计:

AccessID User_ID Source_ID
1 1 1
2 1 2
3 2 1
4 2 2

如果我想将 User_ID = 1 的访问记录更新为 [ {User_ID: 1, Source_ID: 1}, {User_ID: 1, Source_ID: 3} ]

如何删除访问记录“User_ID = 1, Source_ID = 2”并插入访问记录“User_ID = 1, Source_ID = 3”,但保留“User_ID = 1, Source_ID = 1”记录。

使用存储过程?

到目前为止我所拥有的:

C#:

...Create the DB Command and add parameter "Source_ID"..

foreach (var SourceID in user.SourceAccess)
{
  dBCall1.GetCommand().Parameters["Source_ID"].Value = SourceID;
  dBCall1.ExecuteNonQuery;
}

存储过程:

CREATE PROCEDURE [dbo].[UpdateUserSourceAccess]
    @UserID INT,
    @SourceID INT
AS
IF NOT EXISTS (SELECT 1 FROM [UserSourceAccess] WHERE [User_ID] = @UserID AND Source_ID = @SourceID)
    INSERT INTO UserSourceAccess
    ( UserID, SourceID ) VALUES ( @UserID, @SourceID )
...

【问题讨论】:

  • 您如何决定要保留源 1 而不是 2?如果 AccessID 是数组的一部分,您可以轻松地执行 upsert/merge 操作。
  • 也许你可以使用SQL Merge 声明。 WHEN 匹配做操作 1 WHEN 不匹配做操作 2
  • Access_ID 不是数组的一部分,它是 Access 表的主键(用于跟踪用户对源的访问)。我希望能够切换用户源访问(一个用户可以有 1 - 多个源访问)
  • 在 SQL Server 中,您可以创建临时表并在其中插入数组数据。从该表中,您可以比较记录和删除/插入操作。
  • 如果第 3 行和第 4 行不在您的数组中,您会按照什么逻辑保留它们?实际上,您是否有一个需要匹配的Source_ID 列表,但仅适用于单个User_ID

标签: c# sql-server stored-procedures


【解决方案1】:

您尝试做的问题是,您需要能够比较每个用户的 Source_ID 的完整列表,并根据需要插入或删除。

为此,您需要该过程具有要比较的完整列表,因此您最好传递一个表值参数。为此,我通常会保留一些标准的表格类型:

CREATE TYPE IdList (Id int PRIMARY KEY);

GO

然后你需要做一个部分的MERGE:换句话说MERGE整个表,因为这样任何其他用户都会得到他们所有的行删除。而是使用 CTE 预过滤目标表。然后我们可以MERGE 对照 CTE,对照表格参数。

CREATE OR ALTER PROCEDURE [dbo].[UpdateUserSourceAccess]
    @UserID int,
    @SourceIDs dbo.IdList
AS

SET NOCOUNT ON;

WITH t AS (
    SELECT t.AccessID, t.User_ID, t.Source_ID
    FROM YourTable t
    WHERE t.User_ID = @UserID
)
MERGE INTO t
USING @SourceIDs s
  ON s.Id = t.Source_ID
WHEN NOT MATCHED BY SOURCE
  THEN DELETE
WHEN NOT MATCHED BY TARGET
  THEN INSERT (User_ID, Source_ID)
       VALUES (@UserID, s.val)
;

GO

你可以像这样从 C# 调用它

using(var comm = new SqlCommand("UpdateUserSourceAccess", yourConnection))
{
    var table = new DataTable { Columns = { { "Id", typeof(int) } } };
    foreach (var SourceID in user.SourceAccess)
        table.Rows.Add(SourceID);

    comm.Parameters.Add(new SqlParameter("@SourceIDs", SqlDbType.Structured)
    {
        TypeName = "dbo.IdList",
        Direction = ParameterDirection.Input,
        Value = table
    });
    comm.ExecuteNonQuery;
}

【讨论】:

    猜你喜欢
    • 2015-09-20
    • 2016-01-15
    • 2020-12-12
    • 1970-01-01
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    • 2018-06-08
    • 1970-01-01
    相关资源
    最近更新 更多