operaciones - Fecha dinámica de SQL cuando se usa DateDiff
operaciones con fechas sql (6)
¿Hay una manera de pasar el parámetro DatePart de DateDiff como una variable? ¿Para que pueda escribir código que sea similar a esto?
DECLARE @datePart VARCHAR(2)
DECLARE @dateParameter INT
SELECT @datePart = ''dd''
SELECT @dateParameter = 28
SELECT
*
FROM
MyTable
WHERE
DATEDIFF(@datePart, MyTable.MyDate, GETDATE()) < @dateParameter
Las únicas maneras en que puedo pensar en hacerlo es con una sentencia CASE que verifique el valor del parámetro o construyendo el SQL como una cadena y ejecutándolo en un EXEC.
¿Alguien tiene alguna sugerencia "mejor"? La plataforma es MS SQL Server 2005.
Creé una función de valores escalares para hacer esto. Se basa en las soluciones mencionadas anteriormente pero es más fácil de implementar en su código.
CREATE FUNCTION [dbo].[dynamic_dateadd]
(
@unit varchar(5),
@number int,
@dt datetime
)
RETURNS datetime
AS
BEGIN
declare @result datetime
if (@unit=''M'') BEGIN SET @result=(select DATEADD(M,@number,@dt)) END
if (@unit=''WW'') BEGIN SET @result=(select DATEADD(WW,@number,@dt)) END
if (@unit=''D'') BEGIN SET @result=(select DATEADD(D,@number,@dt)) END
if (@unit=''H'') BEGIN SET @result=(select DATEADD(HH,@number,@dt)) END
return(@result)
END
En una consulta puedes usar esta función así:
select startdate, validity_unit, validity_number,
dbo.dynamic_dateadd(valididy_unit,validity_number,startdate) as enddate
from SALES_subscription
De acuerdo con la entrada de BOL en DATEDIFF (sección de argumentos ) para SQL Server 2005,
Estas partes de fecha y abreviaturas no se pueden suministrar como una variable declarada por el usuario.
Por lo tanto, es probable que esté atascado con SQL dinámico o con una sentencia CASE. Pero optaría por una versión CASE en lugar de SQL dinámico.
Definitivamente, el uso de la consulta dinámica como la que se muestra a continuación funciona muy bien, supongo que planea usar solo la abreviatura de @datePart. Recomendaría usar un mínimo de VARCHAR (4) para datepart, esto manejará las abreviaturas como aaaa y mcs. Codificación feliz:
DECLARE @datePart VARCHAR(2)
DECLARE @dateParameter INT
DECLARE @SQLTemp varchar(MAX)
SELECT @datePart = ''dd''
SELECT @dateParameter = 28
set @SQLTemp =''SELECT * FROM MyTable
WHERE DATEDIFF(''+@datePart+'', ''+MyTable.MyDate+'', GETDATE()) < ''+@dateParameter
exec (@SQLTemp)
Lo único que realmente puede hacer aparte de la declaración de caso o sql dinámica sugerida es hacer siempre la fecha en una DatePart granular y luego realizar una conversión ascendente. Sin embargo, esto no es infalible, obtendrá un desbordamiento en la función si intenta realizar un cambio de fecha a granular en un intervalo demasiado grande, por ejemplo, dateiff (segundo, 0, getdate ()). Pero si solo necesita partes como minutos, debería estar bien (verifique dos veces con los valores de fecha máxima que le interesan).
Así por ejemplo
select datediff(minute, 0, getdate())
Si quiero convertir esto en horas, días, etc., solo puedo dividir el resultado por la cantidad apropiada. No tendrá en cuenta los años bisiestos, etc.
No creo que haya mejores maneras de lo que tu describes. El servidor Sql probablemente compile la consulta DATEDIFF en un conjunto de operaciones que dependen del parámetro datepart. Así que necesitarías un CASO, o consultas dinámicas.
Viejo pero todavía válido por desgracia.
Lo hice de forma correcta y solo quiero compartir el código para que no tenga que hacer todo el trabajo molesto que tenía que hacer. Cubre todas las partes de fecha posibles. Simplemente reemplace el nombre de la función y la función de fecha para implementar para otras funciones de fecha de T-SQL.
Copiar y pegar sección
-- SELECT dbo.fn_DateAddFromStringPart(''year'', 1, GETDATE())
CREATE FUNCTION fn_DateAddFromStringPart
(
@Interval VARCHAR(11),
@Increment INT,
@Date SMALLDATETIME
)
RETURNS DATETIME
AS
BEGIN
-- Declare the return variable here
DECLARE @NewDate DATETIME
-- Add the T-SQL statements to compute the return value here
SELECT @NewDate = CASE
WHEN @Interval IN (''year'', ''yy'', ''yyyy'') THEN DATEADD(YEAR, @Increment, @Date)
WHEN @Interval IN (''quarter'', ''qq'', ''q'') THEN DATEADD(QUARTER, @Increment, @Date)
WHEN @Interval IN (''month'', ''mm'', ''m'') THEN DATEADD(MONTH, @Increment, @Date)
WHEN @Interval IN (''dayofyear'', ''dy'', '''') THEN DATEADD(DAYOFYEAR, @Increment, @Date)
WHEN @Interval IN (''day'', ''dd'', ''d'') THEN DATEADD(DAY, @Increment, @Date)
WHEN @Interval IN (''week'', ''wk'', ''ww'') THEN DATEADD(WEEK, @Increment, @Date)
WHEN @Interval IN (''weekday'', ''dw'', ''w'') THEN DATEADD(WEEKDAY, @Increment, @Date)
WHEN @Interval IN (''hour'', ''hh'') THEN DATEADD(HOUR, @Increment, @Date)
WHEN @Interval IN (''minute'', ''mi'', ''n'') THEN DATEADD(MINUTE, @Increment, @Date)
WHEN @Interval IN (''second'', ''ss'', ''s'') THEN DATEADD(SECOND, @Increment, @Date)
WHEN @Interval IN (''millisecond'', ''ms'') THEN DATEADD(MILLISECOND, @Increment, @Date)
WHEN @Interval IN (''microsecond'', ''mcs'') THEN DATEADD(MICROSECOND, @Increment, @Date)
WHEN @Interval IN (''nanosecond'', ''ns'') THEN DATEADD(NANOSECOND, @Increment, @Date)
END
-- Return the result of the function
RETURN @NewDate
END
GO