如何在 C# 中按小时格式(120:15:10)的行求和/分组,如 SQL - SELECT SUM (col1), col 2, col3 GROUP BY col2, col3
Posted
技术标签:
【中文标题】如何在 C# 中按小时格式(120:15:10)的行求和/分组,如 SQL - SELECT SUM (col1), col 2, col3 GROUP BY col2, col3【英文标题】:How to sum/group by rows that w/ hour format(120:15:10) in C# like in SQL - SELECT SUM (col1), col 2, col3 GROUP BY col2, col3 【发布时间】:2014-06-20 21:00:15 【问题描述】:问题: 我有一个带有 C# widowsform 应用程序的 sql 数据库,它带有 datagridview 来显示结果。 我使用流式阅读器从 csv 导入数据。 我需要做一个 SELECT SUM([col1]), [col2], [col3] GROUP BY [col2], [col3]
但我需要求和的列是 nvarchar,表示格式为“000:00:00”的小时
例子:
数据库列: 发生次数|解决方案组|timein_sgroup
SQL Comamand:Select sum(timein_sgroup),occurrence_number,solution_group 按occurrence_number 分组,solution_group
resume:我需要一列中的总小时数(occurence_number),结果按两列分组(occurence_number 和 solution_group)
这是一个系统,用于计算支持小组在事件中保持工作的总时间。
我需要这样的结果 = 一个事件在解决方案组中停留了多少小时:
occnum | groupnamelvl | total hours(SUM)
------------------------------------------
occ001 | sgrouplevel2 | 120:10:10
occ002 | sgrouplevel1 | 20:30:15
occ001 | sgrouplevel1 | 05:15:00
occ010 | sgrouplevel3 | 105:05:00
我看到很多关于 sum Hour 的主题都显示了超过 24 小时的结果,但是当我已经有一列包含这样的行数据时,解决方案不起作用:
occnum | groupnamelvl | hours to sum
------------------------------------------
occ001 | sgrouplevel2 | 120:15:10
occ001 | sgrouplevel2 | 30:10:40
occ001 | sgrouplevel2 | 110:30:00
如何对这一列求和并显示如下结果:
occnum | groupnamelvl | Total_Hours
------------------------------------------
occ001 | sgrouplevel2 | 260:55:50
我使用它,但它仅适用于数据 mior tahn 24h,结果可能大于 24 但小于 99:
SELECT CONVERT(NVARCHAR,
DATEADD(Minute,
SUM(
DATEPART(SECOND,CONVERT(datetime,[colunm],8)) + 60 *
DATEPART(MINUTE,CONVERT(datetime,[colunm],8)) + 3600 *
DATEPART(HOUR,CONVERT(datetime,[colunm],8))
) /60, '00:00:00'), 108) AS [TOTAL] FROM tb
带有查询的 C# 部分:
Database1DataSet ds = new Database1DataSet();
string strSQL = "that query";
SqlCeConnection conn = new SqlCeConnection(@"Data Source=\App_sqlce35\App\DATA\Database1.sdf");
SqlCeDataAdapter da = new SqlCeDataAdapter(strSQL, conn);
try
conn.Open();
ds.Tables.Add("historico");
ds.Tables["historico"].BeginLoadData();
da.Fill(ds.Tables["historico"]);
ds.Tables["historico"].EndLoadData();
tb_histstatusDataGridView.DataSource = ds.Tables["historico"];
在@AsadAli 的帮助下新代码运行良好,但我无法分组:
SqlCeConnection conn = new SqlCeConnection(@"Data Source=\App_sqlce35\DATA\Database1.sdf");
SqlCeCommand cmdselect = new SqlCeCommand("select [col0], [col1], [col2], from tb_histstatus WHERE [col6] <>'';", conn);
try
conn.Open();
SqlCeDataReader res = cmdselect.ExecuteReader();
List<string> times = new List<string>();
while (res.Read())
times.Add((string)res.GetValue(2));
int[] result = new int[3];
foreach (string time in times)
string[] parts = time.Split(':');
for (int i = 0; i < parts.Length; i++)
result[i] += Convert.ToInt32(parts[i]);
TimeSpan ts = TimeSpan.FromSeconds(result[1] * 60 + result[2]);
result[0] += ts.Hours; result[1] = ts.Minutes; result[2] = ts.Seconds;
string resultString = string.Join(":", result);
MessageBox.Show("Total: " + resultString);
【问题讨论】:
该列的数据类型是什么? 使用这些值创建一个 DateTime 对象并与之相加。你已经试过了吗? 我将其设置为 NVARCHAR,因此我尝试转换和转换,但仅在我的小时数小于 24 并且我得到的结果超过 24 小时但仅在 99:00:00 之前工作 将时间的各个部分(小时、分钟和秒)分开并求和呢?您可以使用string.Split(':')
来划分时间。如果不清楚,我可以发布一个示例。
在旁注中,结果是260:55:50
,而不是160:55:50
。
【参考方案1】:
这是我要做的一个例子:
int[] result = new int[3]; //Assuming the format is always as in OP
string[] times = "120:15:10", "30:10:40", "110:30:00" ;
foreach (string time in times)
string[] parts = time.Split(':');
for (int i = 0; i < parts.Length; i++)
result[i] += Convert.ToInt32(parts[i]);
TimeSpan ts = TimeSpan.FromSeconds(result[1] * 60 + result[2]);
result[0] += ts.Hours; result[1] = ts.Minutes; result[2] = ts.Seconds;
string resultString = string.Join(":", result);
输出:260:55:50
编辑:我已更新我的代码以匹配正确的格式。
编辑 2:这是您的使用方法。
SqlCeConnection conn = new SqlCeConnection(@"Data Source=\App_sqlce35\DATA\Database1.sdf");
SqlCeCommand cmdselect = new SqlCeCommand("select [col0], [col1], [col2], [col3], [col4], [col5], [col6] from tb_histstatus WHERE [col6] <>'';", conn);
try
conn.Open();
SqlCeDataReader res = cmdselect.ExecuteReader();
List<string> times = new List<string>();
while (res.Read())
times.Add((string)res.GetValue(6));
int[] result = new int[3];
foreach (string time in times)
string[] parts = time.Split(':');
for (int i = 0; i < parts.Length; i++)
result[i] += Convert.ToInt32(parts[i]);
TimeSpan ts = TimeSpan.FromSeconds(result[1] * 60 + result[2]);
result[0] += ts.Hours; result[1] = ts.Minutes; result[2] = ts.Seconds;
string resultString = string.Join(":", result);
MessageBox.Show("Total: " + resultString);
【讨论】:
@AsadAli - 它正在工作!非常感谢,您给了我很大的帮助,我从这个问题/解决方案中学到了很多东西! 如果需要按两列分组,还有一个问题。我最初的问题是我需要按解决方案代码和区域汇总小时数 您能更具体地谈谈您的问题吗?请编辑您的原始问题以添加详细信息。 @AsadAli 抱歉,我现在编辑并添加描述和示例! @LuisUssuy 我不明白你想做什么。【参考方案2】:我认为您为列选择了错误的数据类型。除了将这些值存储为字符串或日期时间之外,您还可以简单地使用一个整数列来存储总秒数。
260:50:55 = (260*60*60) + (50 * 60) + 55 = 939350 seconds.
现在您对 SUM 聚合函数有了一个完全可管理的值。
当您需要显示值时,您应用公式来分隔部分值
int seconds = GetDurationFromDatabase(); // IE=939350;
TimeSpan ts = new TimeSpan(0,0,seconds);
Console.WriteLine("0:1:2", ts.Days * 24 + ts.Hours, ts.Minutes, ts.Seconds);
【讨论】:
我尝试过但无法导入转换为 int SQL Server 的数据给我错误,并且使用 StreamReader 从 csv 到数据库时出现同样的问题。【参考方案3】: public static void TimeCalc()
string[] t1 = "120:15:10".Split(':');
string[] t2 = "30:10:40".Split(':');
string[] t3 = "110:30:00".Split(':');
TimeSpan ts1 = new TimeSpan(Convert.ToInt32(t1[0]), Convert.ToInt32(t1[1]), Convert.ToInt32(t1[2]));
TimeSpan ts2 = new TimeSpan(Convert.ToInt32(t2[0]), Convert.ToInt32(t2[1]), Convert.ToInt32(t2[2]));
TimeSpan ts3 = new TimeSpan(Convert.ToInt32(t3[0]), Convert.ToInt32(t3[1]), Convert.ToInt32(t3[2]));
TimeSpan ts = ts1.Add(ts2).Add(ts3);
Console.WriteLine((ts.Hours + (ts.Days * 24)).ToString() + ":" + ts.Minutes.ToString() + ":" + ts.Seconds.ToString());
这行得通。有点不优雅,但很有效......
假设 "times": 是一个字符串列表[],那么你可以这样做:
string[] t1 = "120:15:10".Split(':');
string[] t2 = "30:10:40".Split(':');
string[] t3 = "110:30:00".Split(':');
List<string[]> times = new List<string[]>();
times.Add(t1);
times.Add(t2);
times.Add(t3);
TimeSpan ts = new TimeSpan();
foreach (var item in times)
TimeSpan tsa = new TimeSpan(Convert.ToInt32(item[0]), Convert.ToInt32(item[1]), Convert.ToInt32(item[2]));
ts = (ts == TimeSpan.Zero) ? tsa : ts.Add(tsa);
Console.WriteLine((ts.Hours + (ts.Days * 24)).ToString() + ":" + ts.Minutes.ToString() + ":" + ts.Seconds.ToString());
【讨论】:
这看起来不错,但我需要说我不是 C# 程序员,我现在才开始编程,不知道如何在我的查询中使用它:( 好吧,这个特定的部分将在您从查询中获得结果之后出现。一旦你得到了你的价值观,你就可以操纵它们。 1.从数据库中获取数据; 2. 验证它们是字符串且格式正确; 3.计算; 4. 对结果做任何你需要做的事情。 我会试试这个然后给你一个反馈 对不起,如果我的查询有大约 100 行,我真的不知道如何实现这个原因,如果查询结果来自一列和多行,我如何求和(timespan ts.add),我需要使用while吗? 对不起,但它不起作用,因为我需要它更动态,这样我需要把每一行字符串 []t 但是手动工作!以上是关于如何在 C# 中按小时格式(120:15:10)的行求和/分组,如 SQL - SELECT SUM (col1), col 2, col3 GROUP BY col2, col3的主要内容,如果未能解决你的问题,请参考以下文章