从c#创建两个日期范围值之间的日期

时间:2012-07-05 06:57:33

标签: c# sql linq date datediff

我对(My)Sql与c#的日期差异有疑问。
在我的数据库中,我有一个包含如下日期范围的表:

------------------------
From date      to date
-------------------------
2012-07-01    2012-07-03
2012-07-05    2012-07-07
2012-07-10    2012-07-12
2012-07-13    2012-07-16
--------------------------

从这些范围来看,我想计算所有包含的日期,即:

2012-07-01 
2012-07-02 
2012-07-03 
2012-07-05 
2012-07-06 
2012-07-07 
2012-07-10 
2012-07-11 
2012-07-12 
2012-07-13 
2012-07-14 
2012-07-15
2012-07-16

SELECT DATEDIFF('2012-01-01', '2012-02-02')无法正常工作, 它只给出总天数...我希望它之间的所有日期,包括范围的日期(FromDate和ToDate)。

你能告诉我如何实现这个(在SQL或C#中)吗?

3 个答案:

答案 0 :(得分:0)

如果我理解正确,您的表格包含以下内容:

------------------------
From date      to date
-------------------------
2012-07-01    2012-07-03
2012-07-05    2012-07-07
2012-07-10    2012-07-12
2012-07-13    2012-07-16
--------------------------

并且您希望针对它运行SQL并返回列出的每个“发件日期”和“迄今”之间的所有日期。

简单地说(即没有考虑太难),MySql不这样做 - 它从表中返回现有记录。由于您已经在c#应用程序中,从MySql读取记录并创建自己的所有相关日期列表似乎更容易(尽管这取决于您当时想要用它们做什么)。

答案 1 :(得分:0)

我提供了两种可能的解决方案,首先是在C#中使用LINQ,第二种在SQL中使用递归CTE技术来生成日期。随意选择你喜欢的那个。

予。使用LINQ的解决方案:

您提到您正在使用C# - 在这种情况下,您可以利用LINQ,解决方案是以下程序(可以在LinqPad或VisualStudio中运行的控制台应用程序示例)。

    private static void Main(string[] args)
    {
        var query1 = from r in RangeTable.AsQueryable() select r;
        query1.Dump("List of ranges:");

        Console.WriteLine();
        query1.CreateDates().Dump("Result list of dates:");

        Console.ReadLine();
    }

其中RangeTable是将范围表作为可查询对象列表返回的属性(例如,使用LinqToEntityLinqToSQL)。

有趣的部分是扩展方法 CreateDates

    public static IQueryable<DateTime> CreateDates(this IQueryable<DateRange> rtbl)
    {
        var result = new List<DateTime>();

        foreach (var dr in rtbl)
        {
            var q = from i in Enumerable.Range(0, dr.CalcDays())
                    select (DateTime)dr.fromDate.AddDays(i);
            foreach (var d in q) result.Add(d);
        }

        return result.AsQueryable<DateTime>();
    }

此函数使用简单的扩展方法CalcDays计算fromDatetoDate之间的天数(如果fromDate和toDate相等,则故意返回1):

    public static int CalcDays(this DateRange dr)
    {
        var days = (int)(dr.toDate - dr.fromDate).TotalDays + 1;
        return days;
    }

现在有关RangeTable功能的一些细节。它需要类DateRange,它实现了日期范围的两个属性:

public class DateRange
{
    public DateTime fromDate;
    public DateTime toDate;
}

在此示例中,为简单起见,RangeTable在没有数据库连接的情况下定义,但也可以使用LinqToSQL或LinqToEntity:

    private static List<DateRange> RangeTable
    {
        get
        {
            var result = new List<DateRange>() {
                new DateRange() { fromDate = new DateTime(2012, 07, 01), toDate = new DateTime(2012, 07, 03) },
                new DateRange() { fromDate = new DateTime(2012, 07, 05), toDate = new DateTime(2012, 07, 07) },
                new DateRange() { fromDate = new DateTime(2012, 07, 10), toDate = new DateTime(2012, 07, 12) },
                new DateRange() { fromDate = new DateTime(2012, 07, 13), toDate = new DateTime(2012, 07, 16) }
            };
            return result;
        }
    }

最后,如果您没有LinqPad并且想要在VisualStudio中使用该示例,则可以轻松地定义两个转储扩展方法,如下所示:

    const string dateMask = "yyyy-MM-dd";

    public static void Dump(this IQueryable<DateRange> item, string msg)
    {
        Console.WriteLine(msg);
        foreach (var i in item)
        {
            Console.WriteLine(string.Format("{0} to {1}", i.fromDate.ToString(dateMask), i.toDate.ToString(dateMask)));
        }
    }

    public static void Dump(this IQueryable<DateTime> item, string msg)
    {
        Console.WriteLine(msg);
        foreach (var i in item)
        {
            Console.WriteLine(string.Format("{0}", i.ToString(dateMask)));
        }
    }

将它们与其他扩展方法一起放入顶级public static class Extensions注意:DateRange是顶级类,方法RangeTable是在内部Program类中定义的。

样本产生以下输出:

    List of ranges:
    2012-07-01 to 2012-07-03
    2012-07-05 to 2012-07-07
    2012-07-10 to 2012-07-12
    2012-07-13 to 2012-07-16

    Result list of dates:
    2012-07-01
    2012-07-02
    2012-07-03
    2012-07-05
    2012-07-06
    2012-07-07
    2012-07-10
    2012-07-11
    2012-07-12
    2012-07-13
    2012-07-14
    2012-07-15
    2012-07-16

最后一点:

LinqToEntityLinqToSQL是数据库的“桥梁”。

它们是对象关系映射器,它通过使用适当的数据库驱动程序(通过您指定的数据库连接)将LINQ语句转换为SQL并“及时”提交SQL查询,并隐藏有关的实现特定详细信息。数据库,因此您可以专注于编写标准化的LINQ查询。

在此示例中,您需要修改属性RangeTable,以便它查询mySQL数据库并返回IQueryable对象。 您需要做的就是以下内容:

  • 添加到LinqPad的新连接,然后向下钻取到您需要的表格,最后拖动&amp;删除查询(或者,如果名称已匹配,只需添加连接,然后单击“连接”)。
  • 使用LinqToEntities:添加新项到项目中,在“数据”中选择“ADO.NET实体数据模型”,然后选择“从数据库生成”,添加所需的数据库连接,添加表格。它将生成 Model1.edmx 文件。如果您使用 Nortwind 进行测试,那么示例查询将如下所示:

        var entities = new NorthwindEntities1();
        entities.Connection.Open();
        var query1 = from c in entities.Customers select c;
    

II。使用SQL的解决方案:

您还可以使用T-SQL 2008中提供的公用表表达式(又称CTE)来解决此问题:

with 
    sampleTable as (
        select   CAST('2012-07-05' as DATETIME) fromDt
                ,CAST('2012-07-08' as DATETIME) toDt
        union
        select   CAST('2012-08-01' as DATETIME) fromDt
                ,CAST('2012-08-11' as DATETIME) toDt
    ),
    calcdiff as (
        select  DATEDIFF(day, fromDt, toDt) d 
                ,*
        from sampleTable
    ),
    recursion as (
            select fromDt as dt, toDt from calcdiff
        union all
            select dateadd(day, 1, dt) dt2, toDt from recursion
            where dateadd(day, 1, dt)<=toDt
    )
select dt as Result from recursion
order by dt

SampleTable可以替换为您的“真实”SQL表,它仅用于此示例的完整性,calcdiff计算日期差异,recursion计算所需的所有日期递归:联合的第一部分是递归的锚,它是强制性的。请注意,CTE递归中需要union all,否则T-SQL将不执行查询。

如果由于递归级别而出现错误,只需附加

option (maxrecursion 365);

这将允许“更深入”的递归,例如,如果您计算1年的日期,则需要它。

答案 2 :(得分:0)

感谢所有我在C#中修复它..无法在mysql中找到任何东西。

dtDetails是一个数据表,其值来自DB(fromdate和date)

然后我创建了另一个数据表并存储了(fromdate - todate)

中的所有值

然后我将使用该数据表。

if (dtDetails.Rows.Count > 0)

{ foreach (DataRow dr in dtDetails.Rows) { DateTime startingDate = Convert.ToDateTime( dr["fromdate"]); DateTime endingDate = Convert.ToDateTime(dr["todate"]); DateTime newdate; for (newdate = startingDate; newdate <= endingDate; newdate = newdate.AddDays(1)) { DataRow dr2 = dt2.NewRow(); dt2.Rows.Add(newdate); } } }