web-dev-qa-db-fra.com

Étage d'une date dans le serveur SQL

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

Disons que j'ai une date de 2008-09-17 12: 56: 53.430 , le rendement du revêtement de sol devrait alors ê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ème: 2008-09-17 12: 56: 53.000
65
Portman

La clé consiste à utiliser DATEADD et DATIFF avec l'énumération de la plage de temps SQL approprié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 utilisez le sol à la seconde, vous obtiendrez souvent un dépassement arithmétique si vous utilisez 0. Choisissez donc une valeur connue dont la garantie est inférieure à la date et à l'heure que vous tentez de sol.

94
Portman

Dans SQL Server, voici un petit truc pour le faire:

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

Vous transformez le DateTime en un float, qui représente la Date en tant que partie entière et l'Heure en tant que fraction d'un jour écoulé. Coupez cette partie décimale, puis relancez-la en DateTime et vous aurez minuit au début de la journée.

Ceci est probablement plus efficace que tous les éléments DATEADD et DATEDIFF. C'est certainement beaucoup plus facile à taper.

28
Chris Wuestefeld

En développant la solution Convert/Cast, Microsoft SQL Server 2008 permet d'effectuer les opérations suivantes:

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

Il suffit de remplacer getdate() par n'importe quelle colonne datetime.

Il n'y a aucune condition impliquée dans cette conversion.

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

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

Je ne pense pas non plus que la conversion des chaînes soit utilisée, mais je ne peux pas parler de comparaison entre l'efficacité réelle et les estimations chiffrées.

11
Moe Cazzell

J'ai utilisé la réponse de @ Portman à plusieurs reprises au fil des ans comme référence lorsque le revêtement de sol date et a transformé son fonctionnement en une fonction que vous pouvez trouver utile.

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

Je vous demande, si vous décidez de passer à la vôtre supérieure, de bien vouloir aussi faire la même votation @ La réponse de Portman , mon code étant un dérivé de son

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
6
Dan Atkinson

La fonction CONVERT () peut également le faire, en fonction du style utilisé.

2
Joel Coehoorn

Dommage, ce n'est pas Oracle, ou vous pourriez utiliser trunc () ou to_char ().

Mais j'avais des problèmes similaires avec SQL Server et utilisais les méthodes CONVERT () et DateDiff (), comme référencé ici

1
typicalrunt

Il y a plusieurs façons de peler ce chat =)

select convert(datetime,convert(varchar,CURRENT_TIMESTAMP,101))
0
Sean

DateAdd avec DateDiff peut vous aider à effectuer de nombreuses tâches différentes. Par exemple, vous pouvez rechercher le dernier jour d'un mois et le dernier jour du mois précédent ou suivant. 

----Last Day of Previous Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))
LastDay_PreviousMonth
----Last Day of Current Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
LastDay_CurrentMonth
----Last Day of Next Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0))
LastDay_NextMonth

La source

0
pinaldave