it-swarm-eu.dev

Pianifica una data nel server SQL

In SQL Server, come si "floor" un DATETIME al secondo/minuto/ora/giorno/anno?

Diciamo che ho una data di 2008-09-17 12: 56: 53.430 , quindi l'output di pavimentazione dovrebbe essere:

  • Anno: 2008-01-01 00: 00: 00.000
  • Mese: 2008-09-01 00: 00: 00.000
  • Giorno: 2008-09-17 00: 00: 00.000
  • Ora: 2008-09-17 12: 00: 00.000
  • Minuto: 2008-09-17 12: 56: 00.000
  • Secondo: 2008-09-17 12: 56: 53.000
65
Portman

La chiave è usare DATEADD e DATEDIFF insieme all'enumerazione SQL timespan appropriata.

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

Notare che quando si esegue la pavimentazione entro il secondo, si otterrà spesso un overflow aritmetico se si utilizza 0. Quindi, selezionare un valore noto che è garantito essere inferiore al tempo di trasmissione che si sta tentando di eseguire.

94
Portman

In SQL Server ecco un piccolo trucco per farlo:

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

Lanciate il DateTime in un float, che rappresenta la Data come la parte intera e il Tempo come la frazione di un giorno che viene passato. Elimina quella parte decimale, quindi restituiscilo a un DateTime e hai mezzanotte all'inizio di quel giorno.

Questo è probabilmente più efficiente di tutte le cose DATEADD e DATEDIFF. È certamente molto più facile da digitare.

28
Chris Wuestefeld

Espandendo la soluzione Convert/Cast, in Microsoft SQL Server 2008 è possibile eseguire le seguenti operazioni:

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

Basta sostituire getdate() con qualsiasi colonna che sia un datetime.

Non ci sono stringhe coinvolte in questa conversione.

Questo è ok per le query o gli aggiornamenti ad hoc, ma per i join chiave o l'elaborazione molto utilizzata potrebbe essere meglio gestire la conversione all'interno dell'elaborazione o ridefinire le tabelle per avere chiavi e dati appropriati.

Nel 2005, puoi usare il piano di messier: cast(floor(cast(getdate() as float)) as datetime)

Non credo che usi la conversione di stringhe, ma non posso parlare di confrontare l'efficienza effettiva con le stime di poltrona.

11
Moe Cazzell

Ho usato @ la risposta di Portman molte volte nel corso degli anni come riferimento quando le date del pavimento e hanno spostato il suo lavoro in una funzione che potresti trovare utile.

Non rivendico le sue prestazioni e le fornisco semplicemente come uno strumento per l'utente.

Chiedo che, se decidi di revocare questa risposta, per favore anche upvote @ risposta di Portman , poiché il mio codice è un suo derivato.

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

Utilizzo:

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

Anche la funzione CONVERT () può fare ciò, a seconda dello stile che si usa.

2
Joel Coehoorn

Peccato che non sia Oracle, altrimenti potresti usare trunc () o to_char ().

Ma ho avuto problemi simili con SQL Server e ho usato i metodi CONVERT () e DateDiff (), come riferito qui

1
typicalrunt

Ci sono diversi modi per skinare questo gatto =)

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

DateAdd insieme a DateDiff può aiutare a svolgere molte attività diverse. Ad esempio, puoi trovare l'ultimo giorno di qualsiasi mese e trovare l'ultimo giorno del mese precedente o successivo. 

----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

Fonte

0
pinaldave