Этот ответ следует за форматом T-SQL. Я рассматриваю эту проблему как одно из линейного времени между двумя точками даты в формате datetime, назовите их Time1 и Time2; Time1 должен быть привязан к значению «старше во времени», которое вы имеете в виду (например, дата рождения или дата создания виджета или дата начала поездки), а Time2 следует выровнять со значением «более новое время» (например, дата моментального снимка или датой завершения виджета или датой завершения поездки).
DECLARE @Time1 DATETIME
SET @Time1 = '12/14/2015'
DECLARE @Time2 DATETIME
SET @Time2 = '12/15/2016'
Решение использует простые измерения, преобразования и вычисления последовательных пересечений нескольких циклов разной длины; здесь: Century, Decade, Year, Month, Day (Спасибо, майянский календарь за концепцию!). Быстрая благодарность: я благодарю других участников Stack Overflow за то, что они показали мне некоторые функции компонента в этом процессе, которые я сшил вместе. Я положительно оценил их в свое время на этом форуме.
Сначала постройте горизонт, который представляет собой линейный набор пересечений циклов Century, Decade, Year, Month, incremental by 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 точки даты в «гггг -mm '(подумайте об этом как о координатах на всей ткани). Сохраните оригинальную дату-время версии точек, а также:
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: Я называю это «сырой расстояние», так как месяц компонент «гггг-мм» кардинального расстояние может быть слишком много; компоненты дневного цикла в течение месяца необходимо сравнить, чтобы увидеть, должно ли это значение в прошлом месяце рассчитываться. В этом примере, в частности, исходное расстояние вывода равно «12». Но это не так, как 12/14, до 12/15, так что прошло всего 11 полных месяцев - его просто один день застенчивый, истекающий через 12-й месяц. Поэтому мы должны ввести внутримесячный дневной цикл, чтобы получить окончательный ответ. Вставьте «месяц, день» сравнение положения между, чтобы определить, является ли дата последней точкой месяц считается номинально, или нет:
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» теперь наш выход. И поэтому я надеюсь, что это поможет. Благодаря!
2009-01-31 - 2009-02-28. Это 0 или 1 месяц? –
это должно быть 0 – oscarkuo