77 votes

Plancher une date dans le serveur SQL

Dans SQL Server, comment puis-je "plancher" une DATETIME à la seconde/minute/heure/jour/année ?

Disons que j'ai une date de 2008-09-17 12:56:53.430 alors la sortie du plancher devrait être :

  • Année : 2008-01-01 00:00:00.000
  • Mois : 2008-09-01 00:00:00.000
  • Jour : 2008-09-17 00:00:00.000
  • Heure : 2008-09-17 12:00:00.000
  • Minute : 2008-09-17 12:56:00.000
  • Deuxièmement : 2008-09-17 12:56:53.000

115voto

Portman Points 15878

La clé est d'utiliser DATEADD y DATEDIFF avec l'énumération SQL appropriée de la durée.

declare @datetime datetime;
set @datetime = getdate();
select @datetime;
select dateadd(year,datediff(year,0,@datetime),0);
select dateadd(month,datediff(month,0,@datetime),0);
select dateadd(day,datediff(day,0,@datetime),0);
select dateadd(hour,datediff(hour,0,@datetime),0);
select dateadd(minute,datediff(minute,0,@datetime),0);
select dateadd(second,datediff(second,'2000-01-01',@datetime),'2000-01-01');
select dateadd(week,datediff(week,0,@datetime),-1); --Beginning of week is Sunday
select dateadd(week,datediff(week,0,@datetime),0); --Beginning of week is Monday

Notez que lorsque vous planifiez à la seconde, vous obtiendrez souvent un dépassement arithmétique si vous utilisez 0. Choisissez donc une valeur connue qui est garantie comme étant inférieure à la date que vous essayez de planifier.

1 votes

La date à partir de laquelle vous calculez votre compensation ne doit pas nécessairement se situer dans le passé. N'importe quelle date fera l'affaire, à condition qu'elle soit elle-même 'FLOOR'ed à l'intervalle en question. Si la date de base est dans le futur, vous obtenez simplement une valeur de décalage négative...

0 votes

Pour passer à la semaine, utilisez ceci si le dimanche est le premier jour de la semaine ... select dateadd(week,datediff(week,0,@datetime),-1)

0 votes

Utilisez ceci si le lundi est le premier jour de la semaine ... select dateadd(week,datediff(week,0,@datetime),0)

31voto

Chris Wuestefeld Points 1137

Dans SQL Server, il existe une petite astuce pour y parvenir :

SELECT CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS DATETIME)

Vous convertissez le DateTime en un float, qui représente la date comme la partie entière et l'heure comme la fraction de jour qui s'est écoulée. Enlevez la partie décimale, puis transformez le tout en DateTime, et vous obtenez minuit au début de ce jour.

C'est probablement plus efficace que tous les trucs DATEADD et DATEDIFF. C'est certainement plus facile à taper.

1 votes

En fait, il y a 25 % de caractères en plus que dateadd(day,datediff(day,0,@datetime),0), ce qui n'est pas plus facile à taper. C'est aussi 15% moins efficace.

9 votes

@Portman - Y a-t-il une base pour votre affirmation selon laquelle il est 15% moins efficace ?

3 votes

Le coulage vers le plancher nuit aux performances car il ignore les index de date. Avec SQL 2008, il est préférable d'utiliser les fonctions datediff ou CAST( [field] AS TIME) ou CAST( [field] as DATE).

12voto

Moe Cazzell Points 41

En développant la solution Convert/Cast, dans Microsoft SQL Server 2008, vous pouvez faire ce qui suit :

cast(cast(getdate() as date) as datetime)

Il suffit de remplacer getdate() avec toute colonne qui est une date.

Il n'y a pas de ficelles dans cette conversion.

Cela convient pour les requêtes ou les mises à jour ad hoc, mais pour les jointures de clés ou les traitements fortement utilisés, il peut être préférable de gérer la conversion au sein du traitement ou de redéfinir les tables pour qu'elles aient les clés et les données appropriées.

En 2005, vous pouvez utiliser le sol le plus désordonné : cast(floor(cast(getdate() as float)) as datetime)

Je ne pense pas non plus qu'il utilise la conversion de chaîne, mais je ne peux pas parler de la comparaison entre l'efficacité réelle et les estimations de salon.

7voto

Dan Atkinson Points 6043

J'ai utilisé La réponse de @Portman Au fil des ans, nous avons souvent utilisé cette fonction comme référence lors de l'établissement des dates et nous l'avons intégrée dans une fonction qui pourrait vous être utile.

Je ne prétends pas à ses performances et je le fournis simplement comme un outil pour l'utilisateur.

Si vous décidez de voter cette réponse, je vous demande de voter également La réponse de @Portman car mon code est un dérivé du sien.

IF OBJECT_ID('fn_FloorDate') IS NOT NULL DROP FUNCTION fn_FloorDate
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_FloorDate] (
  @Date DATETIME = NULL,
  @DatePart VARCHAR(6) = 'day'
)
RETURNS DATETIME
AS
BEGIN
  IF (@Date IS NULL)
    SET @Date = GETDATE();

  RETURN
  CASE
    WHEN LOWER(@DatePart) = 'year' THEN DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'month' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'day' THEN DATEADD(DAY, DATEDIFF(DAY, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'hour' THEN DATEADD(HOUR, DATEDIFF(HOUR, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'minute' THEN DATEADD(MINUTE, DATEDIFF(MINUTE, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'second' THEN DATEADD(SECOND, DATEDIFF(SECOND, '2000-01-01', @Date), '2000-01-01')
    ELSE DATEADD(DAY, DATEDIFF(DAY, 0, @Date), 0)
  END;
END

Utilisation :

DECLARE @date DATETIME;
SET @date = '2008-09-17 12:56:53.430';

SELECT
  @date AS [Now],--2008-09-17 12:56:53.430
  dbo.fn_FloorDate(@date, 'year') AS [Year],--2008-01-01 00:00:00.000
  dbo.fn_FloorDate(default, default) AS [NoParams],--2013-11-05 00:00:00.000
  dbo.fn_FloorDate(@date, default) AS [ShouldBeDay],--2008-09-17 00:00:00.000
  dbo.fn_FloorDate(@date, 'month') AS [Month],--2008-09-01 00:00:00.000
  dbo.fn_FloorDate(@date, 'day') AS [Day],--2008-09-17 00:00:00.000
  dbo.fn_FloorDate(@date, 'hour') AS [Hour],--2008-09-17 12:00:00.000
  dbo.fn_FloorDate(@date, 'minute') AS [Minute],--2008-09-17 12:56:00.000
  dbo.fn_FloorDate(@date, 'second') AS [Second];--2008-09-17 12:56:53.000

0 votes

Je vous suggère d'utiliser case lower(@DatePart) when 'year'..., plutôt que case when lower(... pour éviter tout le code inutile et les conversions inférieures.

2voto

Joel Coehoorn Points 190579

El CONVERT() La fonction peut également être utilisée, selon le style que vous utilisez.

2 votes

Nous avons constaté que CONVERT() peut être de 10% à 5x moins performant que dateadd/datediff. SQL impose une pénalité pour la conversion entre les types numériques et les chaînes de caractères, et inversement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X