c# - 通过传递逗号分隔值删除记录 SQL Server 和 C#

标签 c# sql sql-server

我尝试使用以下查询和 ado.net ExecuteNonQuery() 方法将多个值作为逗号分隔字符串传递,从而从 SQL Server 数据库表中删除记录。这里我传递表名、列名和逗号分隔值。

string delQuery = "DELETE FROM " + delTblName + 
                  " WHERE " + delColumnName + " IN (" + toDel+ ")";

如果 toDel 中的完整值列表没有问题,则删除过程成功。假设如果外键与任何一个值发生冲突,则整个语句将被终止,并且不会删除任何记录。

由于 toDel 变量中的元素数量很大,我无法使用顺序处理,也无法根据要求使用存储过程。

我需要根据成功的元素进行删除,并从此方法返回错误的元素。任何帮助,将不胜感激。

使用以下代码并使用参数

try
{
   using (var sc = new SqlConnection(dbConnString))
     using (var cmd = sc.CreateCommand())
     {
         sc.Open();
         cmd.CommandText = "DELETE FROM @delTblName WHERE @delColumnName IN ( @valConcat) ";                                       

         cmd.Parameters.AddWithValue("@delTblName", tblName);


         cmd.Parameters.AddWithValue("@delColumnName", delColumnName);


         cmd.Parameters.AddWithValue("@valConcat", nosConcat);


         cmd.CommandType = CommandType.Text;

         rowsAffected = rowsAffected + cmd.ExecuteNonQuery();
     }
}
catch
{

}

出现此错误 - 必须声明表变量“@delTblName”。

最佳答案

无论是否使用存储过程,您都会有两个相互矛盾的要求:

  1. 您想要批量删除行,而不是逐行删除。为了速度。
  2. 您希望删除操作完成时部分忽略可能违反约束的情况。

我不知道如何制作DELETE声明部分起作用。一条语句是最小原子工作量,因此如果 1000 行中有一行违反了约束,则整个语句将回滚。

这导致了以下通用想法。在尝试 DELETE 之前在影响多行的一条语句中,请确保可以删除受影响行的整个列表。明确检查数据中是否没有任何内容可以阻止您要删除的行被删除。实际检查取决于您的限制。识别那些无法删除的行并将它们从主 DELETE 中删除列表。

示例

两个表 - TestMasterTestDetails具有一对多关系。

CREATE TABLE [dbo].[TestMaster](
    [ID] [int] NOT NULL,
    [MasterData] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_TestMaster] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
))

CREATE TABLE [dbo].[TestDetails](
    [ID] [int] NOT NULL,
    [MasterID] [int] NOT NULL,
    [DetailData] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_TestDetails] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
))
GO

ALTER TABLE [dbo].[TestDetails]  WITH CHECK 
ADD  CONSTRAINT [FK_TestDetails_TestMaster] FOREIGN KEY([MasterID])
REFERENCES [dbo].[TestMaster] ([ID])
GO

ALTER TABLE [dbo].[TestDetails] CHECK CONSTRAINT [FK_TestDetails_TestMaster]
GO

一些示例数据:

INSERT INTO [dbo].[TestMaster] ([ID],[MasterData]) VALUES
(1, 'Master1'),
(2, 'Master2'),
(3, 'Master3'),
(4, 'Master4');

INSERT INTO [dbo].[TestDetails] ([ID],[MasterID],[DetailData]) VALUES
(10, 1, 'Detail10'),
(11, 1, 'Detail11'),
(20, 2, 'Detail20');

简单尝试DELETE项目(1, 2, 3, 4) :

DELETE FROM [dbo].[TestMaster]
WHERE ID IN (1, 2, 3, 4);

这失败了:

Msg 547, Level 16, State 0, Line 13
The DELETE statement conflicted with the REFERENCE constraint "FK_TestDetails_TestMaster". The conflict occurred in database "AdventureWorks2014", table "dbo.TestDetails", column 'MasterID'.
The statement has been terminated.

我们只能删除那些没有相应详细信息的主行。在这个例子中它只是 3, 4 .

查找MasterID不能先删除:

SELECT DISTINCT [dbo].[TestDetails].MasterID
FROM [dbo].[TestDetails]
WHERE [dbo].[TestDetails].MasterID IN (1, 2, 3, 4);

返回结果:

MasterID
1
2

编辑您的原始 ID 列表并从中删除冲突的 ID,然后您可以运行最终的 DELETE :

DELETE FROM [dbo].[TestMaster]
WHERE ID IN (3, 4);

单个查询

而不是运行单独的 SELECT ,通过网络向客户端检索冲突ID列表,调整原始ID列表,运行最终的DELETE您可以进行一个查询来完成这一切。对于这个简单的示例,它可以如下所示:

DELETE FROM [dbo].[TestMaster]
WHERE 
    [dbo].[TestMaster].ID IN (1, 2, 3, 4)
    AND [dbo].[TestMaster].ID NOT IN
    (
        SELECT [dbo].[TestDetails].MasterID
        FROM [dbo].[TestDetails]
        WHERE [dbo].[TestDetails].MasterID IN (1, 2, 3, 4)
    );

此查询将仅删除 ID 为 3 和 4 的两行。

关于c# - 通过传递逗号分隔值删除记录 SQL Server 和 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35314913/

相关文章:

c# - 是什么使我无法调整Windows窗体对象的大小(缩小)?

C# 静态方法和属性 : Object reference not set to an instance of an object

sql - 混淆/屏蔽/打乱个人信息

sql - 案例陈述和答案的除法始终为零

java - 如何在触发器的帮助下更新不同 sql 表中的行

c# - 在 C#/.Net 中以编程方式模拟浏览器

c# - 使用 iTextSharp 合并加密的 Pdf 文件

SQL/Oracle 10g - 触发器问题

sql-server - 使用 SQL 将日期范围拆分为多行

sql - ROW_Count() 根据顺序重新开始