目前我正在编写一个速度非常重要的应用程序。该应用程序处理许多记录,最后,我想更新它们被处理的记录。测试版有以下逻辑可以正常工作:
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;我觉得,像往常一样,有更好的方法来解决这个问题。
答案 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子查询。