Esta respuesta sigue el formato T-SQL. Conceptualizo este problema como una de una distancia de tiempo lineal entre dos puntos de fecha en formato datetime, llámalos Time1 y Time2; Time1 debe estar alineado con el valor 'anterior en el tiempo' con el que está tratando (por ejemplo, una fecha de nacimiento o una fecha de creación de widget o una fecha de inicio de viaje) y Time2 debe estar alineado con el valor 'más nuevo en el tiempo' (por ejemplo, una fecha de instantánea o una fecha de finalización de widget o una fecha de punto de control de viaje).
DECLARE @Time1 DATETIME
SET @Time1 = '12/14/2015'
DECLARE @Time2 DATETIME
SET @Time2 = '12/15/2016'
La solución aprovecha medición simple, la conversión y los cálculos de las intersecciones de serie de ciclos múltiples de diferentes longitudes; aquí: Siglo, Década, Año, Mes, Día (¡gracias calendario maya por el concepto!). Una rápida nota de agradecimiento: agradezco a otros colaboradores de Stack Overflow por mostrarme algunas de las funciones de los componentes en este proceso que he cosido. He valorado positivamente estos en mi tiempo en este foro.
Primero, construya un horizonte que sea el conjunto lineal de las intersecciones de los ciclos Siglo, Decenio, Año, Mes, incrementales por mes. Use la función cartesiana de unión cruzada para esto. (Piense en esto como la creación de la tela de la que vamos a cortar una longitud entre dos puntos de 'AAAA-MM' con el fin de medir la distancia):
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
A continuación, convertir sus puntos de fecha TIME1 y Time 2 en el 'aaaa -mm 'formato (Piense en estos como los puntos de corte coordinados en toda la tela). Conservar el original de fecha y hora versiones de los puntos así:
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
A continuación, seleccione la distancia ordinal de unidades 'AAAA-MM', menos uno para convertir la distancia cardinal (es decir, cortar un trozo de paño de la la nada en los puntos de corte identificados y obtener su medición en bruto):
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: yo llamo a esto una 'distancia prima' porque el componente mes de la 'aaaa-mm' distancia cardenal puede ser uno demasiados; los componentes del ciclo diurno dentro del mes deben compararse para ver si este valor del último mes debe contar. Específicamente en este ejemplo, la distancia de salida sin procesar es '12'. Pero esto es incorrecto ya que el 12/14 es antes del 12/15, por lo que solo han transcurrido 11 meses completos, es solo un día antes de que transcurra el 12 ° mes. Por lo tanto, tenemos que traer el ciclo del día intra-mes para llegar a una respuesta final. Inserte una comparación posición 'mes, día' entre la de determinar si el mes más reciente punto de la fecha cuenta nominalmente, o no:
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: La respuesta correcta del '11' es ahora nuestra producción. Y entonces, espero que esto ayude. ¡Gracias!
2009-01-31 a 2009-02-28. ¿Eso es 0 o 1 mes completo? –
esto debería ser un 0 – oscarkuo