首先,让我们谈谈如何获得这个月初。方法有很多种,我觉得DATEFROMPARTS()最直观(见Simplify Date Period Calculations in SQL Server):
DECLARE @FirstOfMonth date = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);
SELECT @FirstOfMonth;
-- result:
-- 2021-09-01
现在,上个月的最后一个星期六必须在本月第一天之前的 1 到 7 天之间。所以我们可以生成一个由 7 个连续数字组成的序列,然后从每月的第一天减去这些天数,如下所示:
DECLARE @FirstOfMonth date = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);
SELECT @FirstOfMonth;
;WITH n(n) AS
(
SELECT 1 UNION ALL
SELECT n + 1 FROM n WHERE n < 7
)
SELECT d = DATEADD(DAY, -n, @FirstOfMonth) FROM n;
/* result:
2021-08-31
2021-08-30
2021-08-29
2021-08-28
2021-08-27
2021-08-26
2021-08-25 */
要确定星期六是什么,您要么需要依赖DATEPART(WEEKDAY, date) - 这又受SET DATEFIRST 的影响,或者您需要依赖DATENAME(WEEKDAY, date) - 而后者又受SET LANGUAGE 的影响。我会倾向于语言更稳定(英语),所以:
DECLARE @FirstOfMonth date = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);
SELECT @FirstOfMonth;
;WITH n(n) AS
(
SELECT 1 UNION ALL
SELECT n + 1 FROM n WHERE n < 7
),
d(d) AS
(
SELECT DATEADD(DAY, -n, @FirstOfMonth)
FROM n
)
SELECT LastMonthLastSaturday = d
FROM d
WHERE DATENAME(WEEKDAY, d) = 'Saturday';
-- result:
-- 2021-08-28
但这是一个主观的要求 - 如果您不能依赖其中一个,请获取日历表,那么它就是这样的:
SELECT LastMonthLastSaturday = MAX(TheDate)
FROM dbo.Calendar
WHERE TheDayOfWeekName = 'Saturday'
AND TheDate < DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);