C# 从datatable中提取两个内容的总和
我在SQL Server数据库中有一个包含许多列的表,但重要的列是C# 从datatable中提取两个内容的总和,c#,sql,sql-server,datatable,C#,Sql,Sql Server,Datatable,我在SQL Server数据库中有一个包含许多列的表,但重要的列是LoggedState和InteractionType 我需要找到中断代理的数量和空闲代理的数量 我试过的 它工作得很好,但我想问的是,是否有一种方法(如分组)可以避免使用foreach语句 var breakAgents = from row in DTgraph.AsEnumerable() where row["LoggedState"].ToString().Trim().ToLower() == "break" sele
LoggedState
和InteractionType
我需要找到中断代理的数量和空闲代理的数量
我试过的
它工作得很好,但我想问的是,是否有一种方法(如分组)可以避免使用foreach
语句
var breakAgents = from row in DTgraph.AsEnumerable()
where row["LoggedState"].ToString().Trim().ToLower() == "break"
select row;
var breakAgentsCount = breakAgents.Count();
及
您可以像这样执行sql查询:
select
sum(case when LoggedState = "break" then 1 else 0 end) break_count,
sum(case when LoggedState = "activo" and InteractionType is null then 1 else 0 end) active_count
from table_name
使用LINQ提供的计数函数,以下解决方案应该可以工作:
// Cast the rows to a collection of DataRows.
IEnumerable<DataRow> collection = DTgraph.Rows.Cast<DataRow>();
// Get the number of Break Agents.
int numberOfBreakAgents = collection.Count(row => row["LoggedState"].ToString().Trim().ToLower() == "break");
// Get the number of Idel Agents.
int numberOfIdelAgents = collection.Count(row => row["LoggedState"].ToString().Trim().ToLower() == "activo" && row["InteractionType"] == DBNull.Value);
//将行强制转换为数据行集合。
IEnumerable collection=DTgraph.Rows.Cast();
//获取中断代理的数量。
int numberOfBreakAgents=collection.Count(行=>row[“LoggedState”].ToString().Trim().ToLower()=“break”);
//获取Idel代理的数量。
int numberOfIdelAgents=collection.Count(行=>row[“LoggedState”].ToString().Trim().ToLower()==“activo”&&row[“InteractionType”]==DBNull.Value);
强制转换用于允许在DataRow集合上使用LINQ
另一个选项是将DataRow集合强制转换为DataRow类型的列表。然后使用ForEach(也是LINQ)来确定代理类型:
List<DataRow> collection = DTgraph.Rows.Cast<DataRow>().ToList();
collection.ForEach(row =>
{
if (row["LoggedState"].ToString().Trim().ToLower() == "break")
numberOfBreakAgents++;
else if (row["LoggedState"].ToString().Trim().ToLower() == "activo" && row["InteractionType"] == DBNull.Value)
numberOfIdelAgents++;
});
List collection=DTgraph.Rows.Cast().ToList();
collection.ForEach(行=>
{
如果(行[“LoggedState”].ToString().Trim().ToLower()=“break”)
numberOfBreakAgents++;
else if(行[“LoggedState”].ToString().Trim().ToLower()==“activo”&&row[“InteractionType”]==DBNull.Value)
numberOfIdelAgents++;
});
上面的示例与您的示例非常相似,但编写得稍短一些,并且没有使用两个字符串(LoggedState和InteractionType)。您可以使用Linq中的
Group
函数:
var loggedStateGroups = dt.AsEnumerable().GroupBy(d => d["LoggedState"].ToString(), (group, row) => new
{
LoggedState = group,
AllCount = row.Count(),
NullCount = row.Where(r => r["InteractionType"] == DBNull.Value).Count()
});
它将按LoggedState分组,每个匹配行的计数(AllCount
)和InteractionType为DBNull.Value
(NullCount
)的行的计数
然后,我们可以通过执行以下操作来选择所需的计数:
int numberOfBreakAgents = loggedStateGroups.Where(y => y.LoggedState == "break").First().AllCount;
int numberOfIdelAgents = loggedStateGroups.Where(y => y.LoggedState == "activo").First().NullCount;
注意,我只是先使用
,假设您总是有结果。如果不总是有结果,则应使用FirstOrDefault
并执行空检查
您可以在使用组之前进行筛选,方法是根据您的数据在其中添加以下
.Where(r => r["LoggedState"].ToString() == "break" || r["LoggedState"].ToString() == "activo")
我已使用以下设置对此进行了测试:
DataTable dt = new DataTable();
dt.Columns.Add("LoggedState");
dt.Columns.Add("InteractionType");
dt.Rows.Add("break", "inter1");
dt.Rows.Add("activo", DBNull.Value);
dt.Rows.Add("break", "inter1");
dt.Rows.Add("break", "inter2");
dt.Rows.Add("activo", "inter2");
对于numberOfBreakAgents
和numberOfIdelAgents
,我分别得到3和1
使用FirstOrDefault进行编辑:
如果您想执行上面提到的空检查,可以将上面的两个int
声明行替换为:
var breakAgents = loggedStateGroups.Where(y => y.LoggedState == "break").FirstOrDefault();
var idelAgents = loggedStateGroups.Where(y => y.LoggedState == "activo").FirstOrDefault();
int numberOfBreakAgents = breakAgents != null ? breakAgents.AllCount : 0;
int numberOfIdelAgents = idelAgents != null ? idelAgents.NullCount : 0;
这是第一个日志数据状态为“break”或null(如果没有)的组。然后,如果组不为null,则分配numberOfBreakAgents
属性;如果组为null,则分配AllCount
属性
对于numberOfIdelAgents
也做了类似的事情,除了我们过滤“activo”组并使用NullCount
属性,因为我们对所有行都不感兴趣,我们只对那些InteractionType为DBNull.Value
的行感兴趣,这些行是我们在NullCount
属性中捕获的
如果结果集包含LoggedState为“activo”的零行或LoggedState为“break”的零行,则必须执行null检查。在这种情况下,.First()
将返回null
,从中访问AllCount
或NullCount
将导致“序列不包含元素”异常
使用以下数据表定义将突出显示差异,因为它会导致使用First()
的numberOfBreakAgents
异常,但使用FirstOrDefault
时正确返回0
DataTable dt = new DataTable();
dt.Columns.Add("LoggedState");
dt.Columns.Add("InteractionType");
dt.Rows.Add("activo", "inter1");
dt.Rows.Add("activo", DBNull.Value);
dt.Rows.Add("activo", "inter1");
dt.Rows.Add("activo", "inter2");
dt.Rows.Add("activo", "inter2");
这可能不关我的事,但你似乎在第3行有一个多余的分号,不应该在那里。@Matthijs谢谢你在你的第一行,没有在行中的位置更改为使DTgraph成为IEumerableeterDBNull.Value
你有)
。为什么是)
?对不起,那是个错误-把它取出来了。+1表示努力。我还没有找到写答案,因为我的队友删除了一些数据。我没有表,我只有存储过程。这个查询可以满足您的需要,您可以在存储过程中使用它。我可以使用存储过程,我在小组里工作,我没有很多权限。你们能更新你们的答案并使用第一个或默认的pleae吗+1使用默认值中的第一个时,您删除了activo
条件中的null检查。这对我来说是非常重要的,我认为没有必要先默认,因为现在结果是空的,尽管你的代码给了我零,这很好,我不认为我这样做了。activo
上的空检查位于填充组的NullCount
属性的联接中。在我的FirstOrDefault
代码中,我正在检查是否有任何与“activo”匹配的LoggedStates,如果有,我将采用NullCount(与“break”类似的,在其中的行数,而不是AllCount)组。@MarcoDinatsoli我已再次更新了答案以添加更多说明。我认为您可能确实需要空检查,但我对您的数据了解不够,无法确定。我尝试了您的第一种方法,但我一直得到零,尽管我可以看到结果有值扫描您检查集合是否已填充?因此,在演员阵容结束后。
var breakAgents = loggedStateGroups.Where(y => y.LoggedState == "break").FirstOrDefault();
var idelAgents = loggedStateGroups.Where(y => y.LoggedState == "activo").FirstOrDefault();
int numberOfBreakAgents = breakAgents != null ? breakAgents.AllCount : 0;
int numberOfIdelAgents = idelAgents != null ? idelAgents.NullCount : 0;
DataTable dt = new DataTable();
dt.Columns.Add("LoggedState");
dt.Columns.Add("InteractionType");
dt.Rows.Add("activo", "inter1");
dt.Rows.Add("activo", DBNull.Value);
dt.Rows.Add("activo", "inter1");
dt.Rows.Add("activo", "inter2");
dt.Rows.Add("activo", "inter2");