C# 每个月两个日期之间的LINQ到SQL之夜
在DB中,我有一个包含签入和签出日期的预订室集合,比如: ID |签入|签出 2017年1月1日至2017年1月3日 2017年1月29日至2017年2月3日 2017年2月4日至2017年2月5日 (格式为dd/MM/yyyy) 现在我想统计一下每个月有多少个晚上被预订,结果应该如下所示: ID |区域|夜间 1 | 01/2017 | 5 2 | 02/2017 | 3C# 每个月两个日期之间的LINQ到SQL之夜,c#,sql,linq,date,C#,Sql,Linq,Date,在DB中,我有一个包含签入和签出日期的预订室集合,比如: ID |签入|签出 2017年1月1日至2017年1月3日 2017年1月29日至2017年2月3日 2017年2月4日至2017年2月5日 (格式为dd/MM/yyyy) 现在我想统计一下每个月有多少个晚上被预订,结果应该如下所示: ID |区域|夜间 1 | 01/2017 | 5 2 | 02/2017 | 3 var result = (from boo in context.BookingRooms
var result = (from boo in context.BookingRooms
group boo by new { boo.CheckIn.Year, boo.CheckIn.Month } into book
orderby book.Key.Year descending, book.Key.Month descending
select new NightsPerMonth
{
Area = book.Key.Month + " / " + book.Key.Year,
Nights = ??
}).ToList();
到目前为止,这就是我所拥有的,但问题是,如果我按入住人数进行分组,那么前几个月入住的人将不在分组中,而且如果我成功分组,我不知道如何计算当前分组月份的夜数(避免计算上一个月或下一个月的夜数,即使签出或签入在本月之外),这样LINQ到SQL就不会失败
谢谢你的建议,我想你的要求对于linq查询来说是相当复杂的。 我建议两种方法来解决这个问题 方法1: 这是我的sql查询以获得所需的结果,您可以创建存储过程或函数来使用它
DECLARE @SampleData AS TABLE (Id int IDENTITY (1,1), Checkin Date, Checkout date)
INSERT INTO @SampleData VALUES ('2017-01-01', '2017-01-03'), ('2017-01-29', '2017-02-03'), ('2017-02-04', '2017-02-05')
;WITH temps AS
(
SELECT CAST(MIN(sd.Checkin) AS Date) AS MinCheckDate, CAST(max(sd.Checkout) AS Date) as MaxCheckDate
FROM @SampleData sd
)
-- Calculate all months from min-checkin-date to max-checkout-date.
-- By Recursive function
,allMonth AS
(
SELECT datepart(month,t.MinCheckDate) AS [Month],
datepart(year, t.MinCheckDate) AS [Year],
datefromparts(datepart(year, t.MinCheckDate) , datepart(month, t.MinCheckDate) ,1) AS StartMonthDate ,
EOMONTH(datefromparts(datepart(year, t.MinCheckDate) , datepart(month, t.MinCheckDate) ,1)) AS EndMonthDate
FROM temps t
UNION ALL
SELECT datepart(month,dateadd(month, 1, am.StartMonthDate)) AS [Month],
datepart(year, dateadd(month, 1, am.StartMonthDate)) AS [Year],
datefromparts(datepart(year, dateadd(month, 1, am.StartMonthDate)) , datepart(month, dateadd(month, 1, am.StartMonthDate)) ,1) AS StartMonthDate ,
EOMONTH(datefromparts(datepart(year, dateadd(month, 1, am.StartMonthDate)) , datepart(month, dateadd(month, 1, am.StartMonthDate)) ,1)) AS EndMonthDate
FROM allMonth am
CROSS JOIN temps t
WHERE dateadd(month, 1, am.StartMonthDate) <= t.MaxCheckDate
)
SELECT CONCAT(am.[Month],'/',am.[Year]) AS Area,
SUM(
DATEDIFF(day,
CAST(IIF( am.StartMonthDate <= sd.Checkin, sd.Checkin, am.StartMonthDate) AS DATE),
CAST(IIF( am.EndMonthDate < sd.Checkout , dateadd(dd, 1,am.EndMonthDate), sd.Checkout) AS date) -- if Checkout > End of month, then End of month will be calculate as a night
) ) AS Nights
FROM allMonth am
LEFT JOIN @SampleData sd ON am.StartMonthDate BETWEEN sd.Checkin AND sd.Checkout OR am.EndMonthDate BETWEEN sd.Checkin AND sd.Checkout
OR sd.Checkin BETWEEN am.StartMonthDate AND am.EndMonthDate OR sd.Checkout BETWEEN am.StartMonthDate AND am.EndMonthDate
GROUP BY am.[Month],am.[Year]
OPTION (MAXRECURSION 0)
班级
public class BookingRooms
{
public int Id { get; set; }
public DateTime Checkin { get; set; }
public DateTime Checkout { get; set; }
}
public class NightsPerMonth
{
public string Area
{
get
{
return string.Format("{0}/{1}", Month, Year);
}
}
public int Month { get; set; }
public int Year { get; set; }
public int Nights { get; set; }
}
和功能
public List<NightsPerMonth> GetNightsPerMonth(List<BookingRooms> lstBookRooms)
{
if (lstBookRooms == null || lstBookRooms.Count == 0) return null;
var result = new List<NightsPerMonth>();
var minCheckin = lstBookRooms.Min(x => x.Checkin);
var maxCheckout = lstBookRooms.Max(x => x.Checkout);
var currentMonth = minCheckin;
while (currentMonth <= maxCheckout)
{
result.Add(new NightsPerMonth
{
Month = currentMonth.Month,
Year = currentMonth.Year,
Nights = GetNumberNightsOfMonth(currentMonth, lstBookRooms)
});
currentMonth = currentMonth.AddMonths(1);
}
return result;
}
private int GetNumberNightsOfMonth(DateTime currentMonth, List<BookingRooms> lstBookRooms)
{
var startDateOfMonth = new DateTime(currentMonth.Year, currentMonth.Month, 1);
var endDateOfMonth = startDateOfMonth.AddMonths(1).AddDays(-1);
return lstBookRooms.Where(x => IsBookRoom(startDateOfMonth, endDateOfMonth, x.Checkin, x.Checkout))
.Sum(x => NumberNightsBookRoom(startDateOfMonth, endDateOfMonth, x.Checkin, x.Checkout));
}
private bool IsBookRoom(DateTime startDateOfMonth, DateTime endDateOfMonth, DateTime checkin, DateTime checkout)
{
if (startDateOfMonth >= checkin && startDateOfMonth <= checkout) return true;
if (endDateOfMonth >= checkin && endDateOfMonth <= checkout) return true;
if (checkin >= startDateOfMonth && checkin <= endDateOfMonth) return true;
if (checkout >= startDateOfMonth && checkout <= endDateOfMonth) return true;
return false;
}
private int NumberNightsBookRoom(DateTime startDateOfMonth, DateTime endDateOfMonth, DateTime checkin, DateTime checkout)
{
var startTimeSpan = startDateOfMonth <= checkin ? checkin : startDateOfMonth;
// if Checkout > End of month, then End of month will be calculate as a night
var endTimeSpan = endDateOfMonth < checkout ? endDateOfMonth.AddDays(1) : checkout;
return (endTimeSpan - startTimeSpan).Days;
}
公共列表GetNightsPerMonth(列出书房)
{
if(lstBookRooms==null | | lstBookRooms.Count==0)返回null;
var result=新列表();
var minCheckin=lstBookRooms.Min(x=>x.Checkin);
var maxCheckout=lstBookRooms.Max(x=>x.Checkout);
var currentMonth=minCheckin;
while(当前月份为BookRoom(每月开始日期、每月结束日期、x.签入、x.签出))
.Sum(x=>NumberNightsBookRoom(开始月底,结束月底,x.签入,x.签出));
}
private bool IsBookRoom(DateTime startDateOfMonth、DateTime endDateOfMonth、DateTime签入、DateTime签出)
{
如果(startDateOfMonth>=checkin&&startDateOfMonth=checkin&&endDateOfMonth=startDateOfMonth&&checkin=startDateOfMonth&&checkout)在您的第一个表中有ID 2出现两次?这个ID代表什么?@davidele它只是表的自动递增键-它没有任何进一步的用途,它不完全是我想要的(不是LINQ)但它解决了问题!谢谢。
public List<NightsPerMonth> GetNightsPerMonth(List<BookingRooms> lstBookRooms)
{
if (lstBookRooms == null || lstBookRooms.Count == 0) return null;
var result = new List<NightsPerMonth>();
var minCheckin = lstBookRooms.Min(x => x.Checkin);
var maxCheckout = lstBookRooms.Max(x => x.Checkout);
var currentMonth = minCheckin;
while (currentMonth <= maxCheckout)
{
result.Add(new NightsPerMonth
{
Month = currentMonth.Month,
Year = currentMonth.Year,
Nights = GetNumberNightsOfMonth(currentMonth, lstBookRooms)
});
currentMonth = currentMonth.AddMonths(1);
}
return result;
}
private int GetNumberNightsOfMonth(DateTime currentMonth, List<BookingRooms> lstBookRooms)
{
var startDateOfMonth = new DateTime(currentMonth.Year, currentMonth.Month, 1);
var endDateOfMonth = startDateOfMonth.AddMonths(1).AddDays(-1);
return lstBookRooms.Where(x => IsBookRoom(startDateOfMonth, endDateOfMonth, x.Checkin, x.Checkout))
.Sum(x => NumberNightsBookRoom(startDateOfMonth, endDateOfMonth, x.Checkin, x.Checkout));
}
private bool IsBookRoom(DateTime startDateOfMonth, DateTime endDateOfMonth, DateTime checkin, DateTime checkout)
{
if (startDateOfMonth >= checkin && startDateOfMonth <= checkout) return true;
if (endDateOfMonth >= checkin && endDateOfMonth <= checkout) return true;
if (checkin >= startDateOfMonth && checkin <= endDateOfMonth) return true;
if (checkout >= startDateOfMonth && checkout <= endDateOfMonth) return true;
return false;
}
private int NumberNightsBookRoom(DateTime startDateOfMonth, DateTime endDateOfMonth, DateTime checkin, DateTime checkout)
{
var startTimeSpan = startDateOfMonth <= checkin ? checkin : startDateOfMonth;
// if Checkout > End of month, then End of month will be calculate as a night
var endTimeSpan = endDateOfMonth < checkout ? endDateOfMonth.AddDays(1) : checkout;
return (endTimeSpan - startTimeSpan).Days;
}