c# - 从数据表中提取两件事的总和

标签 c# sql sql-server datatable

我的 SQL Server 数据库中有一个表,其中包含许多列,但重要的列是 LoggedStateInteractionType

我需要找到中断座席的数量和空闲座席的数量。

我尝试过的

SqlCommand GraphCmd = new SqlCommand("getAgentStatues", Graphsqlcon);
SqlParameter tdate = new SqlParameter();
GraphCmd.CommandType = CommandType.StoredProcedure; ;
SqlDataAdapter DAGraph = new SqlDataAdapter(GraphCmd);
DataSet DSGraph = new DataSet();
DSGraph.Clear();
DAGraph.Fill(DSGraph);
DataTable DTgraph = new DataTable();
DTgraph = DSGraph.Tables[0];

int numberOfBreakAgents = 0;
int numberOfIdelAgents = 0;
foreach (DataRow row in DTgraph.Rows)
{
     String LoggedState = row["LoggedState"].ToString().Trim().ToLower();
     String InteractionType = row["InteractionType"].ToString();
     if (LoggedState == "break")
     {
          numberOfBreakAgents++;
     }
     else if ((LoggedState == "activo") && (row["InteractionType"] == DBNull.Value))
     {
          numberOfIdelAgents++;
     }
}

它工作得很好,但我想问是否有一种方法(比如分组)来避免 foreach 语句

最佳答案

您可以使用 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;

请注意,我仅使用 First 假设您始终会得到结果。如果您并不总能得到结果,则应使用 FirstOrDefault 并执行 null 检查。

您可以在使用Group之前进行过滤,方法是根据您的数据添加以下Where

.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");

我分别得到 numberOfBreakAgentsnumberOfIdelAgents31

编辑使用 FirstOrDefault:

如果您想执行上面提到的 null 检查,您可以将上面的两个 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;

这将采用第一个 LoggedState 为“break”的组,如果没有,则为 null。然后,如果该组不为 null,则将 numberOfBreakAgents 分配给 AllCount 属性;如果为 null,则分配 0 属性。

numberOfIdelAgents 执行类似的操作,只不过我们过滤“activo”组并使用 NullCount 属性,因为我们对 all 行,我们只对 InteractionType 为 DBNull.Value 的行感兴趣,这些行是我们在 NullCount 属性中捕获的。

如果结果集包含 LoggedState 为“activo”的零行或 LoggedState 为“break”的零行,则必须进行空检查。在这种情况下,.First() 将返回 null 并从中访问 AllCountNullCount 将导致“序列不包含元素”异常。

使用以下 DataTable 定义将突出显示差异,因为它会导致使用 First()numberOfBreakAgents 出现异常,但在使用时正确返回 0 FirstOrDefault

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");

关于c# - 从数据表中提取两件事的总和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25136264/

相关文章:

c# - 如何通过应用任何二进制运算来检索十进制值?

c# - 如何从我的浏览器查看 soap 服务数据

mysql - MySQL 8.0 中使用的 CONTAINS 关键字是什么?

mysql - 无法深入访问字段多个子查询

sql-server - 从数百个存储过程中解析出完整的动态SQL表达式

c# - 如何使用 MVVM 在组合框中设置默认文本

c# - 在使用 ViewModel 或 DTO 而不是 ORM 生成的实体时,如何保留 IQueryable<T> 的优点?

sql - 连接小时和分钟列以十进制格式显示 SQL 查询

sql-server - sqlcmd 变量缺少值

sql-server - osql.exe可以独立运行吗?