Mejor enfoque para eliminar parte de tiempo de datetime en SQL Server


¿Qué método proporciona el mejor rendimiento al eliminar la porción de tiempo de un campo datetime en SQL Server?

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

O

b) select cast(convert(char(11), getdate(), 113) as datetime)

El segundo método envía algunos bytes más de cualquier manera, pero eso podría no ser tan importante como la velocidad de la conversión.

Ambos también parecen ser muy rápidos, pero podría haber una diferencia en la velocidad cuando se trata de cientos de miles o más filas?

También, es posible que hay métodos aún mejores para obtener deshacerse de la parte de tiempo de un datetime en SQL?

Author: gbn, 2009-07-24

23 answers

Estrictamente, el método a es el que requiere menos recursos:

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

Probado menos intensivo de CPU para la misma duración total de un millón de filas por alguien con demasiado tiempo en sus manos: La forma más eficiente en SQL Server para obtener la fecha de fecha+hora?

Vi una prueba similar en otros lugares con resultados similares también.

Prefiero el DATEADD / DATEDIFF porque:

Edit, Oct 2011

Para SQL Server 2008+, puede enviar a date. O simplemente use date así que no hay tiempo para eliminar.

Edit, Jan 2012

Un ejemplo de lo flexible que es esto: Necesita calcular por hora o fecha redondeada en sql server

Editar, May 2012

No use esto en cláusulas WHERE y similares sin pensar: agregar una función o CAST a una columna invalida el uso del índice. Ver el número 2 aquí: http://www.simple-talk.com/sql/t-sql-programming/ten-common-sql-programming-mistakes /

Ahora, esto tiene un ejemplo de versiones posteriores de SQL Server optimiser administrando CAST hasta la fecha correctamente, pero generalmente será una mala idea ...

Editar, Sep 2018, para fecha2

DECLARE @datetime2value datetime2 = '02180912 11:45' --this is deliberately within datetime2, year 0218
DECLARE @datetime2epoch datetime2 = '19000101'

select DATEADD(dd, DATEDIFF(dd, @datetime2epoch, @datetime2value), @datetime2epoch)
 486
Author: gbn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-19 19:26:52

En SQL Server 2008, puede usar:

CONVERT(DATE, getdate(), 101)
 52
Author: Anto Raja Prakash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-09 06:49:53

Por supuesto, este es un hilo viejo, pero para hacerlo completo.

Desde SQL 2008 puede usar el tipo de datos DATE para que simplemente pueda hacer:

SELECT CONVERT(DATE,GETDATE())
 33
Author: Arjan Fraaij,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-06 13:05:14
SELECT CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)
 19
Author: Gary McGill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-24 12:57:54

En SQL Server 2008, hay un tipo de datos DATE (también un tipo de datos TIME).

CAST(GetDate() as DATE)

O

declare @Dt as DATE = GetDate()
 12
Author: Metaphor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-03 22:54:13

Aquí hay otra respuesta, de otra pregunta duplicada:

SELECT CAST(CAST(getutcdate() - 0.50000004 AS int) AS datetime) 

Este método de número mágico funciona ligeramente más rápido que el método DATEADD. (Parece ~10%)

El tiempo de CPU en varias rondas de un millón de registros:

DATEADD   MAGIC FLOAT
500       453
453       360
375       375
406       360

Pero tenga en cuenta que estos números son posiblemente irrelevantes porque ya son MUY rápidos. A menos que tuviera conjuntos de registros de 100,000 o más, ni siquiera podía obtener el tiempo de CPU para leer por encima de cero.

Considerando el hecho de que DateAdd está destinado para este propósito y es más robusto, yo diría que use DateAdd.

 8
Author: Jeff Meatball Yang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:50
SELECT CAST(CAST(GETDATE() AS DATE) AS DATETIME)
 5
Author: Byju,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-03 13:55:00

Elimine el tiempo en insertos/actualizaciones en primer lugar. En cuanto a la conversión sobre la marcha, nada puede superar a una función definida por el usuario en cuanto a la capacidad de mantenimiento:

select date_only(dd)

La implementación de date_only puede ser lo que quieras, ahora está abstraída y llamar al código es mucho más limpio.

 2
Author: Anton Gogolev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-24 12:55:14

Ver esta pregunta:
¿Cómo puedo truncar una datetime en SQL Server?

Hagas lo que hagas, no uses el método string. Es la peor manera de hacerlo.

 2
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:32

Ya contestado, pero voy a tirar esto por ahí también... esto supuestamente también se preforma bien, pero funciona desechando el decimal (que almacena el tiempo) del flotador y devolviendo solo la parte completa (que es la fecha)

 CAST(
FLOOR( CAST( GETDATE() AS FLOAT ) )
AS DATETIME
)

Segunda vez que encontré esta solución... tomé este código de

 2
Author: Carter Cole,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-09 16:06:45
CAST(round(cast(getdate()as real),0,1) AS datetime)

Este método no utiliza la función string. Date es básicamente un tipo de datos real con dígitos antes del decimal son fracción de un día.

Esto supongo que será más rápido que mucho.

 2
Author: shantanu singh chauhan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-18 14:10:25

Para mí el siguiente código siempre es un ganador:

SELECT CONVERT(DATETIME, FLOOR(CONVERT(FLOAT,GETDATE())));
 2
Author: user1920017,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-20 21:20:31

CUIDADO!

Los métodos a) y b) NO siempre tienen la misma salida!

select DATEADD(dd, DATEDIFF(dd, 0, '2013-12-31 23:59:59.999'), 0)

Salida: 2014-01-01 00:00:00.000

select cast(convert(char(11), '2013-12-31 23:59:59.999', 113) as datetime)

Salida: 2013-12-31 00:00:00.000

(Probado en MS SQL Server 2005 y 2008 R2)

EDITAR: De acuerdo con el comentario de Adam, esto no puede suceder si lee el valor de fecha de la tabla, pero puede suceder si proporciona su valor de fecha como un literal (ejemplo: como un parámetro de un procedimiento almacenado llamado via ADO.NET).

 2
Author: broslav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-22 14:01:46

Seleccione CONVERTIR(char (10), GetDate (), 126)

 2
Author: Diego,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-10 14:11:33

Me gusta mucho:

[date] = CONVERT(VARCHAR(10), GETDATE(), 120)

El código de formato 120 forzará la fecha a la norma ISO 8601:

'YYYY-MM-DD' or '2017-01-09'

Súper fácil de usar en dplyr (R) y pandas (Python)!

 2
Author: emehex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-10 17:58:09

Creo que quieres decir cast(floor(cast(getdate()as float))as datetime)

Real es solo 32 bits, y podría perder cierta información

Esto es lo más rápido cast(cast(getdate()+x-0.5 as int)as datetime)

...aunque solo un 10% más rápido (about 0.49 microseconds CPU vs. 0.58)

Esto fue recomendado, y toma el mismo tiempo en mi prueba justo ahora: DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

En SQL 2008, la función CLR de SQL es aproximadamente 5 veces más rápida de lo que sería usar una función SQL, a 1.35 microsegundos frente a 6.5 microsecciones, lo que indica una sobrecarga de llamadas a funciones mucho menor para una función CLR de SQL frente a una SQL UDF.

En SQL 2005, la función CLR de SQL es 16 veces más rápida, según mis pruebas, en comparación con esta función lenta:

create function dateonly (  @dt datetime )
returns datetime
as
begin
return cast(floor(cast(@dt as float))as int)
end
 1
Author: Aaron West,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-26 04:37:36

¿Qué tal select cast(cast my_datetime_field as date) as datetime)? Esto resulta en la misma fecha, con la hora establecida en 00: 00, pero evita cualquier conversión a texto y también evita cualquier redondeo numérico explícito.

 1
Author: Dr. Drew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-24 08:52:41

Creo que si te quedas estrictamente con TSQL que esta es la forma más rápida de truncar el tiempo:

 select convert(datetime,convert(int,convert(float,[Modified])))

Encontré que este método de truncamiento es aproximadamente un 5% más rápido que el método DateAdd. Y esto se puede modificar fácilmente para redondear al día más cercano de esta manera:

select convert(datetime,ROUND(convert(float,[Modified]),0))
 1
Author: Jamie G,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-26 16:53:03

Aquí hice una función para eliminar algunas partes de un datetime para SQL Server. Uso:

  • El primer parámetro es la fecha y hora a eliminar.
  • El segundo parámetro es un char:
    • s: redondea a segundos; elimina milisegundos
    • m: redondea a minutos; elimina segundos y milisegundos
    • h: redondea a horas; elimina minutos, segundos y milisegundos.
    • d: redondea a días; elimina horas, minutos, segundos y milisegundos.
  • Devuelve el nuevo datetime

create function dbo.uf_RoundDateTime(@dt as datetime, @part as char) returns datetime as begin if CHARINDEX( @part, 'smhd',0) = 0 return @dt; return cast( Case @part when 's' then convert(varchar(19), @dt, 126) when 'm' then convert(varchar(17), @dt, 126) + '00' when 'h' then convert(varchar(14), @dt, 126) + '00:00' when 'd' then convert(varchar(14), @dt, 112) end as datetime ) end

 1
Author: Max Vargas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-26 17:07:58

Por si acaso alguien está buscando aquí una versión de Sybase ya que varias de las versiones anteriores no funcionaron

CAST(CONVERT(DATE,GETDATE(),103) AS DATETIME)
  • Probado en I SQL v11 ejecutándose en Adaptive Server 15.7
 1
Author: Alan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-31 01:32:38

Si es posible, para cosas especiales como esta, me gusta usar funciones CLR.

En este caso:

[Microsoft.SqlServer.Server.SqlFunction]
    public static SqlDateTime DateOnly(SqlDateTime input)
    {
        if (!input.IsNull)
        {
            SqlDateTime dt = new SqlDateTime(input.Value.Year, input.Value.Month, input.Value.Day, 0, 0, 0);

            return dt;
        }
        else
            return SqlDateTime.Null;
    }
 0
Author: tjeuten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-13 14:40:19

Yo, personalmente, casi siempre uso User Defined functions para esto si se trata de SQL Server 2005 (o una versión inferior), sin embargo, debe tenerse en cuenta que hay inconvenientes específicos al usar UDF, especialmente si se aplican a las cláusulas WHERE (ver más abajo y los comentarios sobre esta respuesta para más detalles). Si utiliza SQL Server 2008 (o superior), consulte a continuación.

De hecho, para la mayoría de las bases de datos que creo, agrego estos UDF en justo cerca del comienzo ya que sé que hay un 99% es posible que tarde o temprano los necesite.

Creo uno para "solo fecha" y "solo hora" (aunque el "solo fecha" es, con mucho, el más utilizado de los dos).

Aquí hay algunos enlaces a una variedad de UDF relacionados con la fecha:

Funciones esenciales de Fecha, Hora y DateTime de SQL Server
Función Get Date Only

Ese último enlace muestra no menos de 3 formas diferentes de obtener la fecha solo parte de un campo datetime y menciona algunos pros y contras de cada aproximación.

Si se utiliza un UDF, debe tenerse en cuenta que se debe tratar de evitar el uso del UDF como parte de una cláusula WHERE en una consulta, ya que esto dificultará en gran medida el rendimiento de la consulta. La razón principal de esto es que el uso de un UDF en una cláusula WHERE hace que esa cláusula sea no sargable, lo que significa que SQL Server ya no puede usar un índice con esa cláusula para mejorar la velocidad de ejecución de la consulta. Con referencia a mi propio uso de UDF, usaré con frecuencia el columna de fecha " raw " dentro de la cláusula WHERE, pero aplique el UDF a la columna seleccionada. De esta manera, el UDF solo se aplica al conjunto de resultados filtrado y no a todas las filas de la tabla como parte del filtro.

Por supuesto, el mejor enfoque absoluto para esto es usar SQL Server 2008 (o superior) y separar sus fechas y horas, ya que el motor de base de datos de SQL Server proporciona de forma nativa los componentes de fecha y hora individuales, y puede consultar independientemente sin la necesidad de un UDF u otro mecanismo para extraer la parte fecha u hora de un tipo datetime compuesto.

 0
Author: CraigTP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-30 14:48:29

Usaría:

CAST
(
CAST(YEAR(DATEFIELD) as varchar(4)) + '/' CAST(MM(DATEFIELD) as varchar(2)) + '/' CAST(DD(DATEFIELD) as varchar(2)) as datetime
) 

Creando así efectivamente un nuevo campo a partir del campo de fecha que ya tiene.

 -3
Author: Jabu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-19 12:33:49