改进SQL查询以计算两个连续行之间的时间跨度

时间:2015-11-20 10:26:55

标签: c# sql datatable timespan

所以......我有一张这样的桌子:

RowID | DocID | Time       | DepartmentID
1     | 1001  | 2015-11-20 | 1
2     | 1001  | 2015-11-21 | 2
3     | 1002  | 2015-11-20 | 1
4     | 1001  | 2015-11-25 | 1
5     | 1002  | 2015-11-22 | 3
6     | 1002  | 2015-11-30 | 1

我的目标是在将部门发送给其他部门之前,花时间将部门花费在文档上。

我通过将上面的表从SQL传递到C#中的数据表来成功实现了这一点。然后获取DocsID列表,并迭代抛出该列表中的每个项目,使用DocID过滤数据表,然后计算连续行之间的时间。 所以最终结果如下:

DepartmentID | DocID | Time (Days)
1            | 1001  | 2
2            | 1001  | 5
1            | 1002  | 3
3            | 1002  | 9

问题是C#中的这个功能大约需要30秒才能得到这个结果,所以我正在寻找改进它的方法。
是否有可能只在不使用C#进行任何操作的情况下抛出SQL?

我的C#功能(dt是带有第一个表的数据表):

        List<Int32> listDocIDs = new List<Int32>();
        foreach (DataRow dr in dt.Rows)
        {
            int str = Convert.ToInt32(dr["DocID"].ToString());

            if (!listDocIDs.Contains(str))
                listDocIDs.Add(str);
        }

        DataTable times = new DataTable();

        times.Columns.AddRange(new DataColumn[3] { new DataColumn("DepartmentID", typeof(Int32)),
                        new DataColumn("DocID",typeof(Int32)),
                        new DataColumn("Days",typeof(Int32)) });

        foreach (int DocID in listDocIDs)
        {
            DataTable DocID_times = new DataTable();

            using (SqlConnection conn = new SqlConnection(strCon))
            {
                conn.Open();
                SqlDataAdapter adapter = new SqlDataAdapter("getRecordsByDocID", conn);
                adapter.SelectCommand.Parameters.Add("@DocID", SqlDbType.Int).Value = DocID;
                adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
                adapter.Fill(DocID_times);
                conn.Close();
            }

            int j = 0;
            for (int i = 0; i < DocID_times.Rows.Count; i++)
            {
                j = i + 1;

                if (i < (DocID_times.Rows.Count - 1))
                {
                    DateTime tempo1 = DateTime.ParseExact(DocID_times.Rows[i]["Time"].ToString(), "dd-MM-yyyy HH:mm:ss",
                                   System.Globalization.CultureInfo.InvariantCulture);
                    DateTime tempo2 = DateTime.ParseExact(DocID_times.Rows[j]["Time"].ToString(), "dd-MM-yyyy HH:mm:ss",
                                   System.Globalization.CultureInfo.InvariantCulture);

                    double mins = (tempo2 - tempo1).TotalMinutes;
                    TimeSpan result = TimeSpan.FromMinutes(mins);
                    double days = result.TotalDays;

                    var rows = times.Select(string.Format("DepartmentID = {0} AND DocID = {1}", DepartmentID, DocID));
                    if (rows.Length == 0)
                    {
                        // Add your Row
                        times.Rows.Add(DepartmentID, DocID, days);     
                    }
                    else
                    {
                        // Update your Days
                        rows[0]["days"] = Convert.ToInt32(rows[0]["days"].ToString()) + days;
                    }

                }
            }
        }

1 个答案:

答案 0 :(得分:0)

如果列出所有行,我会计算while循环中记录之间的天数。它可以完全用SQL完成,但它不会像while循环那样好(它可以一次访问两行)。为了能够在SQL中完全执行它,您必须自己加入表,将每个记录与下一个记录连接起来。

IEnumerable<MySummarizedRow> GetSummarizedRows()
{
    using (var entries = GetRowsOrderedByDocIdAndRowId().GetEnumerator())
    {
        if (entries.MoveNext())
        {
            var previous = entries.Current;
            while (entries.MoveNext())
            {
                var current = entries.Current;
                if (current.DocId == previous.DocId)
                    yield return new MySummarizedRow(previous.DepartmentId, current.DocId, current.Time.Substract(previous.Time).TotalDays + 1);

                previous = current;
            }
        }
    }
}

此函数忽略尚未传递给其他部门的文档的行。您可以轻松地更改产生-1天的新行或类似的行。