如何在 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的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中按 ID 对 JSON 数据进行分组

如何在 C# 中按进程获取打开文件句柄的列表?

C#如何将DateTime的12小时格式转换为24小时时间格式????

C#中如何将txt文件在ListView中按列显示

如何在 C# 中按值获取枚举对象?

如何在 C# 中按升序对多维数组进行排序? [复制]