基于条件更新多场的清洁方法?

时间:2014-03-14 23:01:49

标签: c# sql sql-server linq

目前我正在编写一个速度非常重要的应用程序。该应用程序处理许多记录,最后,我想更新它们被处理的记录。测试版有以下逻辑可以正常工作:

string listOfIds = string.Join(", ", listOfIds.Select(q=> q.ID));
_db.ExecuteCommand(string.Format("update table set processed = 1 where id in ({1})", listofIds));

其中listOfIds包含已处理的所有ID的列表。这很好用,但现在我需要设置“处理过的”#39;基于过程中发生的事情,根据不同的价值观。所以我不能只设置processed = 1,它是有条件的。所以listOfIds实际上定义如下:

List<CustomClass> listOfIds = new List<CustomClass>();

class CustomClass
{
    public int Status { get; set; }
    public int ID { get; set; }
}

我的解决方案如下。我没有将所有记录添加到listOfIds,而是必须添加“状态”的每个可能值。到一个单独的清单。像这样:

List<CustomClass> listOfSuccessfulIds = new List<CustomClass>();
List<CustomClass> listOfFailedIds = new List<CustomClass>();
List<CustomClass> listOfSomethingElseIds = new List<CustomClass>();
...
_db.ExecuteCommand(string.Format("update table set processed = 1 where id in ({1})", listOfSuccessfulIds ));
_db.ExecuteCommand(string.Format("update table set processed = 2 where id in ({1})", listOfFailedIds ));
_db.ExecuteCommand(string.Format("update table set processed = 3 where id in ({1})", listOfSomethingElseIds ));

这肯定是功能性的,但看起来很混乱。特别是如果有很多可能性来处理&#39;我觉得,像往常一样,有更好的方法来解决这个问题。

1 个答案:

答案 0 :(得分:1)

如果没有太多不同的值,可以使用case语句:

List<CustomClass> toUpdate = ...
var query = string.Format(@"
    UPDATE table 
    SET processed = CASE {0} ELSE 1/0 END
    WHERE id IN ({1})
    ",
    string.Join(
        " ",
        toUpdate.GroupBy(c => c.Status)
            .Select(g => string.Format("WHEN id IN ({0}) THEN {1}", g.Key, string.Join(",", g.Select(c => c.ID))
    ),
    string.Join(",", toUpdate.Select(c => c.ID))
);

这将提供如下查询:

UPDATE table
SET processed = CASE WHEN id IN (1, 2) THEN 1 WHEN id IN (3, 4) THEN 2 ELSE 1/0 END
WHERE id IN (1, 2, 3, 4)

如果您有大量不同的ID,那么最好生成子查询并加入其中:

var subQuery = string.Join(
    " UNION ALL ", 
    toUpdate.Select(c => string.Format("SELECT {0} AS id, {1} AS status", c.ID, c.Status)
);

然后你会执行如下查询:

UPDATE t
SET t.processed = q.status
FROM table t
JOIN ({subQuery}) q
    ON q.id = t.id

最后,如果这仍然生成太多文本,您可以先将子查询表示的“表”插入临时表(例如使用SqlBulkCopy),然后执行上面的查询加入临时表而不是SELECT ... UNION ALL子查询。