此答案遵循 T-SQL 格式。我将此问题概念化为 datetime 格式的两个日期点之间的线性时间距离之一,称它们为 Time1 和 Time2; Time1 应与您正在处理的“较早的时间”值对齐(例如出生日期或小部件创建日期或旅程开始日期),并且 Time2 应与“较新的时间”值对齐(例如快照日期或小部件完成日期或旅程检查点到达日期)。
DECLARE @Time1 DATETIME
SET @Time1 = '12/14/2015'
DECLARE @Time2 DATETIME
SET @Time2 = '12/15/2016'
该解决方案利用了对不同长度的多个周期的串行交叉点的简单测量、转换和计算;这里:世纪,十年,年,月,日(感谢玛雅日历的概念!)。简短的感谢信:感谢 Stack Overflow 的其他贡献者向我展示了我在此过程中拼接在一起的一些组件功能。我在这个论坛上对这些内容给予了积极评价。
首先,构建一个地平线,它是 Century、Decade、Year、Month 周期的交点的线性集合,按月递增。为此使用交叉连接笛卡尔函数。 (将其视为创建布料,我们将在两个 'yyyy-mm' 点之间切割一段长度以测量距离):
SELECT
Linear_YearMonths = (centuries.century + decades.decade + years.[year] + months.[Month]),
1 AS value
INTO #linear_months
FROM
(SELECT '18' [century] UNION ALL
SELECT '19' UNION ALL
SELECT '20') centuries
CROSS JOIN
(SELECT '0' [decade] UNION ALL
SELECT '1' UNION ALL
SELECT '2' UNION ALL
SELECT '3' UNION ALL
SELECT '4' UNION ALL
SELECT '5' UNION ALL
SELECT '6' UNION ALL
SELECT '7' UNION ALL
SELECT '8' UNION ALL
SELECT '9') decades
CROSS JOIN
(SELECT '1' [year] UNION ALL
SELECT '2' UNION ALL
SELECT '3' UNION ALL
SELECT '4' UNION ALL
SELECT '5' UNION ALL
SELECT '6' UNION ALL
SELECT '7' UNION ALL
SELECT '8' UNION ALL
SELECT '9' UNION ALL
SELECT '0') years
CROSS JOIN
(SELECT '-01' [month] UNION ALL
SELECT '-02' UNION ALL
SELECT '-03' UNION ALL
SELECT '-04' UNION ALL
SELECT '-05' UNION ALL
SELECT '-06' UNION ALL
SELECT '-07' UNION ALL
SELECT '-08' UNION ALL
SELECT '-09' UNION ALL
SELECT '-10' UNION ALL
SELECT '-11' UNION ALL
SELECT '-12') [months]
ORDER BY 1
然后,将您的 Time1 和 Time2 日期点转换为“yyyy-mm”格式(将这些视为整块布料上的坐标切割点)。保留原来的 datetime 版本的点:
SELECT
Time1 = @Time1,
[YYYY-MM of Time1] = CASE
WHEN LEFT(MONTH(@Time1),1) <> '1' OR MONTH(@Time1) = '1'
THEN (CAST(YEAR(@Time1) AS VARCHAR) + '-' + '0' + CAST(MONTH(@Time1) AS VARCHAR))
ELSE (CAST(YEAR(@Time1) AS VARCHAR) + '-' + CAST(MONTH(@Time1) AS VARCHAR))
END,
Time2 = @Time2,
[YYYY-MM of Time2] = CASE
WHEN LEFT(MONTH(@Time2),1) <> '1' OR MONTH(@Time2) = '1'
THEN (CAST(YEAR(@Time2) AS VARCHAR) + '-' + '0' + CAST(MONTH(@Time2) AS VARCHAR))
ELSE (CAST(YEAR(@Time2) AS VARCHAR) + '-' + CAST(MONTH(@Time2) AS VARCHAR))
END
INTO #datepoints
然后,选择'yyyy-mm'单位的序数距离,减去一个以转换为基数距离(即在确定的切割点从整块布料上剪下一块布并得到它的原始尺寸):
SELECT
d.*,
Months_Between = (SELECT (SUM(l.value) - 1) FROM #linear_months l
WHERE l.[Linear_YearMonths] BETWEEN d.[YYYY-MM of Time1] AND d.[YYYY-MM of Time2])
FROM #datepoints d
Raw Output:
我称之为“原始距离”,因为“yyyy-mm”基数距离的月份部分可能太多了;需要比较该月内的天周期分量,以查看上个月的值是否应该计算在内。具体而言,在本示例中,原始输出距离为“12”。但是这个错误,因为 12/14 早于 12/15,因此只有 11 个完整的月份已经过去了——距离第 12 个月只差一天。因此,我们必须引入月内日周期才能得出最终答案。在 之间插入 'month,day' 位置比较以确定最近的日期点月份是否名义上计数:
SELECT
d.*,
Months_Between = (SELECT (SUM(l.value) - 1) FROM AZ_VBP.[MY].[edg_Linear_YearMonths] l
WHERE l.[Linear_YearMonths] BETWEEN d.[YYYY-MM of Time1] AND d.[YYYY-MM of Time2])
+ (CASE WHEN DAY(Time1) < DAY(Time2)
THEN -1
ELSE 0
END)
FROM #datepoints d
Final Output:
'11' 的正确答案现在是我们的输出。所以,我希望这会有所帮助。谢谢!