恕我直言,以下内容不是解决特定问题的方法指导,而是更多的概念验证性内容,展示了SQL的可能性。
因此,让我们说问题是要计算工作日计数,该工作日计数定义为不包括周末和节假日的天数(在当前实施中为可选值)。
假设要计算的期间存储在与联系人关联的表中。
[tblPeriods]
keyPeriodID-自动编号(长),PK
keyContactID-Long,FK(tblContacts)
dteStart-日期/时间
dteEnd-日期/时间
目标是接收包含顺序日期的数据集,该日期属于表中存储的日期时段,不包括周末和节假日。 然后,一个简单的分组查询将返回所需的结果。
步骤1.获取记录。
为了使所有日期都落入时段,我们需要将[tblPeriods]与包含所有顺序日期的数据集进行外部联接。
显然,使用存储所有日期的表不是一个明智的选择。 ;)
更好地动态生成它。
显然,日历日期不过是1-31天数字,1-12个月数字和合理的年数范围的所有可能组合。 当然,不存在的日期(例如12月30日,有时是12月29日)必须省略。
这给出了使用以下数据集的笛卡尔联接的想法:
[tblDays]
lngDay-Long,PK-自然数设置为1-31
[tblMonts]
lngMonth-Long,PK-自然数设置为1-12
[tblYears]
lngYear-Long,PK-自然数集... :) ...让我们说2000-2014
以下查询会将这些值组合到2000-2014年的固定日历中,使用DateSerial()函数的功能将不存在的日期排除在外,以防止在非法的argumnets中包装日期。
查询:[qryFlatCalendar]
SELECT DateSerial(tblYears.lngYear,tblMonths.lngMonth,tblDays.lngDay) AS dteDate,
tblYears.lngYear, tblMonths.lngMonth, tblDays.lngDay
FROM tblYears, tblMonths, tblDays
WHERE tblDays.lngDay=Day(DateSerial([tblYears].[lngYear],[tblMonths].[lngMonth],[tblDays].[lngDay]));
然后,使用[tblPeriods]进行外部联接:
查询:[qryContactsPeriodsDays]
SELECT qryFlatCalendar.*, tblPeriods.keyPeriodID, tblPeriods.keyContactID, tblPeriods.dteStart, tblPeriods.dteEnd
FROM qryFlatCalendar LEFT JOIN tblPeriods ON (tblPeriods.dteStart<=qryFlatCalendar.dteDate) AND (tblPeriods.dteEnd>=qryFlatCalendar.dteDate)
WHERE Not tblPeriods.keyContactID Is Null;
注意查询的ON子句。
在当前的实施中,期间的两端都包括在内。
如果考虑其他逻辑,则应在该位置实现它。
步骤2.不包括周末和节假日。
现在,我们将排除周末和节假日。
并立即出现两个问题-像往常一样一个很容易,而另一个则不容易:)
- 周末放假时间取决于特定国家/地区。
- 假期设置也取决于国家/地区。 问题在于,在某些情况下,每年的假期日期是相同的,在某些情况下,它是使用某些规则计算的,而这些规则并不总是很容易嵌入到关系数据库中。 因此,为简单起见,让我们存储该“不规则”假日的明确的完整日期,而“常规”假日不需要多个具有空值的记录。
这需要几个表:
[tblCountries]
keyCountryID-自动编号(长),PK
txtCountry-文字
[tblCountryDaysOff]
keyContactDayOffID-自动编号(长),PK
keyCountryID-Long,FK(tblCountries)
lngContactDayOff-长
[tblCountryHolidays]
keyCountryHolidayID-自动编号(长),PK
keyCountryID-Long,FK(tblCountries)
txtHolidayName-文字
[tblContacts]
keyContactID-自动编号(长),PK
keyCountryID-Long,FK(tblCountries)
txtContactName-文字
*下表将假期与日期相关联,如果假期发生在每年的特定月份,则使用[lngYear] = Null的单个记录,否则必须创建每年的记录
[tblHolydayDates]
keyHolidayID-自动编号(长),PK
lngDay-长
lngMonth-长
lngYear-长
keyCountryHolidayID-Long,FK(tblCountryHolidays)
现在有两个预加入以获得关联-Contact / DaysOff,Contact / HolidayDate
查询:[qryContactsDaysOff]
SELECT tblContacts.*, tblCountryDaysOff.lngContactDayOff
FROM tblContacts INNER JOIN tblCountryDaysOff
ON tblContacts.keyCountryID = tblCountryDaysOff.keyCountryID;
查询:[qryContactsHolidaysDates]
SELECT tblContacts.*, tblCountryHolidays.keyCountryHolidayID,
tblCountryHolidays.txtHolidayName, tblHolydayDates.keyHolidayID, tblHolydayDates.lngDay, tblHolydayDates.lngMonth, tblHolydayDates.lngYear
FROM (tblContacts INNER JOIN tblCountryHolidays
ON tblContacts.keyCountryID = tblCountryHolidays.keyCountryID)
INNER JOIN tblHolydayDates
ON tblCountryHolidays.keyCountryHolidayID=tblHolydayDates.keyCountryHolidayID;
首先,我们将通过以下外部联接来排除休息日:
查询:[qryContactsPeriodsDaysWODaysOff]
SELECT qryContactsPeriodsDays.*, qryContactsDaysOff.lngContactDayOff
FROM qryContactsPeriodsDays
LEFT JOIN qryContactsDaysOff
ON
(qryContactsPeriodsDays.keyContactID=qryContactsDaysOff.keyContactID) AND (WeekDay(qryContactsPeriodsDays.dteDate)=qryContactsDaysOff.lngContactDayOff)
WHERE qryContactsDaysOff.lngContactDayOff Is Null;
接下来,我们将排除假期:
查询:[qryContactsPeriodsBusinessDays]
SELECT qryContactsPeriodsDaysWODaysOff.keyPeriodID,
qryContactsPeriodsDaysWODaysOff.keyContactID, qryContactsPeriodsDaysWODaysOff.dteDate,
qryContactsHolidaysDates.txtHolidayName
FROM qryContactsPeriodsDaysWODaysOff
LEFT JOIN qryContactsHolidaysDates
ON
(qryContactsPeriodsDaysWODaysOff.lngYear=qryContactsHolidaysDates.lngYear Or qryContactsHolidaysDates.lngYear Is Null)
AND (qryContactsPeriodsDaysWODaysOff.lngMonth=qryContactsHolidaysDates.lngMonth) AND
(qryContactsPeriodsDaysWODaysOff.lngDay=qryContactsHolidaysDates.lngDay) AND
(qryContactsPeriodsDaysWODaysOff.keyContactID=qryContactsHolidaysDates.keyContactID)
WHERE qryContactsHolidaysDates.keyCountryHolidayID Is Null;
步骤3.计算天数。
现在甜点。
查询:[qryContactsPeroidsBusinessDaysCounts]
SELECT qryContactsPeriodsBusinessDays.keyPeriodID,
qryContactsPeriodsBusinessDays.keyContactID,
Count(qryContactsPeriodsBusinessDays.dteDate)
AS CountOfdteDate
FROM qryContactsPeriodsBusinessDays
GROUP BY qryContactsPeriodsBusinessDays.keyPeriodID,
qryContactsPeriodsBusinessDays.keyContactID;
好。
快完成了
但是,工作日计数为零的期间不会出现在结果列表中。
因此,让Uroboros咬住他的尾巴。
查询:[qryFinalJoin]
SELECT tblPeriods.*, Nz(qryContactsPeroidsBusinessDaysCounts.CountOfdteDate,0) AS
lngBusinessDays
FROM tblPeriods
LEFT JOIN qryContactsPeroidsBusinessDaysCounts
ON tblPeriods.keyPeriodID=qryContactsPeroidsBusinessDaysCounts.keyPeriodID;
所附数据库中的PS Holidays列表可能不完整,错误或不相关。
我没有尽力去做一个好人。
:D
PPS好。 今天没有样品,因为允许的最大大小为5k。 :D这是byte.com当前状态的另一个错误。
From: https://bytes.com/topic/access/insights/856583-howto-calculate-business-days-pure-sql-approach