如何在给定值集合的情况下插入新行并从表中删除缺失的行?

时间:2013-07-09 00:54:34

标签: sql sql-server azure-sql-database

假设我有一张包含以下数据的表格。

Id   Value
1  | A
2  | B
3  | C

我需要将此表中的值与一组值同步。我想删除任何不在我的集合中的行,添加行,然后单独留下匹配的行。

鉴于这一系列价值观:

C,D,E

操作后我希望该表包含:

Id   Value
3  | C
4  | D
5  | E

我知道大多数需要多次查询的明显解决方案。我正在寻找的是更有效的可能解决方案。我能以某种方式在这里使用MERGE语句吗?

编辑 - 集合值位于C#集合(List< string>)中,我使用.NET中的标准SqlConnection / SqlCommand来执行查询。

这是我考虑过去除值的事情。但这可能是不赞成的,因为我必须做一些字符串连接才能创建它。

DELETE FROM [MyTable] 
WHERE [Value] NOT IN ('C','D','E')

但是为了添加值,似乎我必须为我的集合中的每个值创建多个IF NOT EXISTS THEN INSERT查询语句。

2 个答案:

答案 0 :(得分:1)

我认为你不能在一个SQL语句中执行此操作,但是你可以创建一个存储过程来完成这项工作:

create procedure upsertnewrecords(
   @collection varchar(max)
  ) as
begin
  delete 
  from yourtable 
  where charindex(','+value+',', ','+@collection+',') = 0

  ;with cte as (
    select split.t.value('.', 'VARCHAR(100)') newvalue  
    from (
      select cast ('<M>' + replace(@collection, ',', '</M><M>') + '</M>' as xml) as String    
    ) t 
    cross apply String.nodes ('/M') AS Split(t)  
  )

  insert into yourtable
  select newvalue 
  from cte
  where newvalue not in 
    (select value from yourtable)
end

此存储过程首先使用CHARINDEX删除当前列表中不存在的值,然后使用CROSS APPLY将逗号分隔列表转换为表值列表,最后通过公用表表达式。

答案 1 :(得分:0)

好的,所以你的收藏是在C#列表中。这使这更容易。这不是最有效的方法,因为它涉及大量查询,并且它可以更好地使用字典,但它是一个解决方案,如果你没有按时间,不想使用字符串连接做一个复杂的查询。

using (SqlConnection connection = new SqlConnection(.....))
{
   connection.Open;

   using (SqlCommand command = new SqlCommand("SELECT ID, Value FROM Table"))
   {
      using (SqlDataReader reader = SqlCommand.ExecuteReader())
      {
         while (reader.Read())
         {
             if (THELIST.Contains(reader["Value"].ToString())
             {

                  THELIST.Remove(reader["Value"].ToString());
             }
             else
             {
                  //Execute a SqlCommand in here to do a DELETE where ID = reader["ID"]
             }

         }

      }

   }

   //Now that you've deleted all the ones that aren't in this list, go through what's left in the list and insert them (only the ones that aren't in the database will be left, since you deleted them as they were found

   foreach (string thing in THELIST)
   {
    //Execute a SqlCommand to do an insert into the database
   }

}