我对(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#中)吗?
答案 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技术来生成日期。随意选择你喜欢的那个。
您提到您正在使用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
是将范围表作为可查询对象列表返回的属性(例如,使用LinqToEntity或LinqToSQL)。
有趣的部分是扩展方法 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
计算fromDate
和toDate
之间的天数(如果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
最后一点:
LinqToEntity和LinqToSQL是数据库的“桥梁”。
它们是对象关系映射器,它通过使用适当的数据库驱动程序(通过您指定的数据库连接)将LINQ语句转换为SQL并“及时”提交SQL查询,并隐藏有关的实现特定详细信息。数据库,因此您可以专注于编写标准化的LINQ查询。
在此示例中,您需要修改属性RangeTable,以便它查询mySQL数据库并返回IQueryable对象。 您需要做的就是以下内容:
使用LinqToEntities:添加新项到项目中,在“数据”中选择“ADO.NET实体数据模型”,然后选择“从数据库生成”,添加所需的数据库连接,添加表格。它将生成 Model1.edmx 文件。如果您使用 Nortwind 进行测试,那么示例查询将如下所示:
var entities = new NorthwindEntities1();
entities.Connection.Open();
var query1 = from c in entities.Customers select c;
您还可以使用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); } } }