在Ado.net C#中动态构建子句

时间:2018-10-28 23:19:14

标签: c# sql-server ado.net

在给定的时间,我将接收大约1000条记录,我必须确定它们是现有记录还是新记录。

如果它们存在,我必须更新记录,如果是新记录,则只需插入它们。我不知道它们是否会存在或全部存在。

我认为最好对数据库进行一次查询,然后尝试查找数据库中是否存在任何查询并将其存储在内存中,然后在内存中检查该集合并进行检查。

最初,我被告知我1个字段足以确定唯一性。所以我以为我可以对数据库中的1个字段执行1个大的子句,但现在我发现情况并非如此,我需要使用3个字段来确定记录是否存在。

这基本上是一个and子句

select * from where columnA = "1" and ColumnB = "2" and ColumnC = "3"

如何在C#ado.net中正确解决此问题?

我猜我将需要具有一些超级where子句?

select * from where (columnA = "1" and ColumnB = "2" and ColumnC = "3") or  (columnA = "4" and ColumnB = "5" and ColumnC = "6") or [....998 more conditional clauses)

如果可能,我愿意提出更好的主意。我仍然认为,一次完成比执行1000次独立查询要好。

2 个答案:

答案 0 :(得分:6)

我只能帮您编写查询请求

        var recordCount = 1000;
        var query = "SELECT * FROM TableName WHERE";
        for (var i = 1; i < recordCount - 2; i += 3)
        {
            query += " (columnA = " + i + " and ColumnB = " + (i + 1) + " and ColumnC = " + (i + 2) + ") or ";
        }

答案 1 :(得分:1)

我写这个答案有点愚蠢,因为我认为您应该能够将其他文章的完整答案整理在一起-但这与我所想到的任何一个问题都不完全相同。

Stackoverflow中已经存在解决此问题的问题和答案-但是,在我的搜索中,我仅发现不是线程安全的答案,并且大多数答案都使用merge

我可以推荐您使用不同的问题和答案,例如 我对Adding multiple parameterized variables to a database in c# 的回答,在这里您可以看到如何在C#上使用表值参数,对Aaron Bertrand对Using a if condition in an insert SQL Server的回答,在这里您可以看到如何创建安全的upsert-但是我没有找到任何可以完全解决这个问题的答案-因此,您可以开始:

首先,您需要在数据库中创建用户定义的表类型:

CERATE TYPE MyTableType AS TABLE
(
     Column1 int NOT NULL,
     Column2 int NOT NULL,
     Column3 int NOT NULL,
     -- rest of the columns in your table goes here
     PRIMARY KEY (Column1, Column2, Column3)
)

然后,创建存储过程:

CREATE stp_UpsertMyTable
(
    @MyTableType dbo.MyTableType readonly -- table valued parameters must be readonly
)
AS

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRANSACTION;

UPDATE t 
SET t.column4 = tvp.column4,
    t.column5 = tvp.column5 -- and so on for all columns that are not part of the key
FROM dbo.MyTable AS t
INNER JOIN @MyTableType AS tvp
    ON t.Column1 = tvp.Column1
    AND t.Column2 = tvp.Column2
    AND t.Column3 = tvp.Column3;

 -- Note: <ColumnsList> should be replaced with the actual columns in the table
INSERT dbo.MyTable(<ColumnsList>)
  SELECT <ColumnsList>
  FROM @MyTableType AS tvp
  WHERE NOT EXISTS
  (
    SELECT 1 FROM dbo.MyTable t
    WHERE t.Column1 = tvp.Column1
    AND t.Column2 = tvp.Column2
    AND t.Column3 = tvp.Column3
  );

COMMIT TRANSACTION;

GO

然后,c#部分很简单:

   
DataTable dt = new DataTable();
dt.Columns.Add("Column1", typeof(int));
dt.Columns.Add("Column2", typeof(int));
dt.Columns.Add("Column3", typeof(int));
dt.Columns.Add("Column4", typeof(string));
dt.Columns.Add("Column5", typeof(string));

// Fill your data table here

using (var con = new SqlConnection("ConnectionString"))
{
    using(var cmd = new SqlCommand("stp_UpsertMyTable", con))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add("@MyTable", SqlDbType.Structured).Value = dt;
        con.Open();
        cmd.ExecuteNonQuery();
    }
}

现在,您可以使用表值参数进行完整而安全的更新,而在C#和sql server之间只有一次往返。