2009-05-28 4 views
7

Sto scrivendo una vista del database per riassumere un gruppo di record in cui il valore in una colonna della data è negli ultimi 7 giorni. Sembra qualcosa di simile:Come evitare l'uso di getdate() in una vista SQL?

CREATE VIEW RecentRecordSum AS 
SELECT  t.ID, 
      SUM(t.SomeValue) AS ValueSum 
FROM  SomeTable t 
WHERE  t.RecordDate >= DATEADD(d,-7,GETDATE()) 
GROUP BY t.ID 

Esiste un modo di fare questo senza avere la GETDATE() direttamente nella clausola dove?

sto usando SQL Server 2000 e il 2005.

Esaminando il piano di query mostra che il costo della chiamata GETDATE() è solo 0,03% di tutta la domanda (che è molto più complessa di quella sopra), quindi le prestazioni non sono un problema, tuttavia mi piace che le mie query siano deterministiche.

Idealmente mi piacerebbe anche esporre il parametro -7 come una colonna in modo che possa essere utilizzato nella clausola where di qualcosa che interroga la vista. Attualmente sto contemplando un numero limitato di visualizzazioni per finestre di 7, 14, 28 giorni.

+0

Non sono sicuro se ho capito la domanda. Dove sarebbe se non nella clausola where? Stai pensando ad una sorta di parametro che passi? – micahtan

+0

Sto assumendo che questo per evitare il colpo di prestazioni di valutare GETDATE() per ogni singola riga del set di risultati. – Joe

+0

Perché pensi che sia valutato per ogni riga? – RedFilter

risposta

6

Un motivo per la tua domanda potrebbe essere quello di rendere la vista più ottimizzabile rimuovendo la trasformazione dei dati. Non può farlo in una vista, avresti bisogno di farne una stored procedure e fare la trasformazione in una variabile:

CREATE PROCEDURE RecentRecordSum AS 

DECLARE @adate DATETIME 

SELECT @adate = DATEADD(d, -7, GETDATE()) 

SELECT  t.ID, 
      SUM(t.SomeValue) AS ValueSum 
FROM  SomeTable t 
WHERE  t.RecordDate >= @adate 
GROUP BY t.ID 
0
SELECT CURRENT_TIMESTAMP 

SELECT {fn NOW()} 

forse ho capito male la domanda, se si sta solo cercando di spostare GetDate() e non sostituirlo si può fare la valutazione in una clausola Avere cioè

CREATE VIEW RecentRecordSum AS 
SELECT  t.ID, 
      SUM(t.SomeValue) AS ValueSum 
FROM  SomeTable t 
GROUP BY t.ID, t.RecordDate 
HAVING  t.RecordDate >= DATEADD(d,-7,GETDATE()) 
0

Se io capisco correttamente la domanda, puoi sempre provare un inner join con un set che contiene GETDATE() come nella seguente query:

SELECT  t.ID, 
      SUM(t.SomeValue) AS ValueSum 
FROM  SomeTable t 
INNER JOIN (SELECT DATEADD(d,-7,GETDATE()) AS MIN_DATE) MIN_DATE_SET 
ON t.RecordDate >= MIN_DATE_SET.MIN_DATE 
GROUP BY t.ID 

EDIT: Ho esaminato un piano di query per uno scenario simile e sono identici. YMMV.

2

Un altro salto nel buio, come tutti gli altri ...

Forse si desidera rendere questa vista indicizzata, che non si sarebbe in grado di fare con getdate(), poiché è una funzione indeterminata. Ho aggirato questo in passato chiamando getdate() dall'interno di un'altra vista che contiene solo

select getdate() 

Questo livello di riferimento indiretto è stato sufficiente per ingannare SQL Server 2000 e mi permette di utilizzare SCHEMABINDING, ma non posso garantire questo funzionerà con le versioni successive.

+0

Verificherò questo aspetto - grazie – geofftnz

+0

Ho provato questo nel 2008. Non funzionava, purtroppo 'Msg 4513, Livello 16, Stato 2, Procedura view_ProductSearch, Linea 5 [Batch Start Line 9] Impossibile lo schema bind view 'dbo .view_ProductSearch'. 'dbo.view_CurrentDate' non è legato allo schema. –

+0

Non che io raccomandi questo, ma potresti creare una funzione CLR che restituisce la data corrente e contrassegnarla come IsDeterministic. – RedFilter

0

Supponendo che si dispone di dati in là della più recente giornata, una sottoquery potrebbe forse lavorare:

CREATE VIEW RecentRecordSum AS 
SELECT  t.ID, 
      SUM(t.SomeValue) AS ValueSum 
FROM  SomeTable t 
WHERE  t.RecordDate >= DATEADD(d,-7,(Select Max(RecordDate) From SomeTable)) 
GROUP BY t.ID