Domanda

(Questo è correlato a Inserire una data nel server SQL .)

Esiste un'espressione deterministica per stabilire un DATETIME? Quando lo uso come formula di colonna calcolata:

DATEADD(dd, DATEDIFF(dd, 0, [datetime_column]), 0)

viene visualizzato un errore quando inserisco un indice su quella colonna:

  

Impossibile creare l'indice perché la colonna chiave 'EffectiveDate' non è deterministica o imprecisa.

Ma sia DATEDIFF che DATEADD sono funzioni deterministiche per definizione. Dov'è il trucco? È possibile?

È stato utile?

Soluzione

La mia ipotesi è che si tratti di un bug di qualche tipo. In SQL 2005 sono stato in grado di creare una vista così indicizzata senza problemi (il codice è sotto). Quando ho provato a eseguirlo su SQL 2000 ho riscontrato lo stesso errore che stai riscontrando.

Il seguente sembra funzionare su SQL 2000, ma ricevo un avviso che l'indice verrà ignorato E dovresti convertirlo ogni volta che hai selezionato dalla vista.

CONVERT(CHAR(8), datetime_column, 112)

Funziona in SQL 2005:

CREATE TABLE dbo.Test_Determinism (
    datetime_column DATETIME    NOT NULL    DEFAULT GETDATE())
GO

CREATE VIEW dbo.Test_Determinism_View
WITH SCHEMABINDING
AS
    SELECT
        DATEADD(dd, DATEDIFF(dd, 0, [datetime_column]), 0) AS EffectiveDate
    FROM
        dbo.Test_Determinism
GO

CREATE UNIQUE CLUSTERED INDEX IDX_Test_Determinism_View ON dbo.Test_Determinism_View (EffectiveDate)
GO

Altri suggerimenti

La tua colonna [datetime_column] ha un valore predefinito impostato su " getDate () " ??

In tal caso, poiché la funzione getdate () non è deterministica, questo causerà questo errore ...

Se una funzione definita dall'utente è deterministica o non deterministica dipende da come la funzione è codificata. Le funzioni definite dall'utente sono deterministiche se:

  1. La funzione è associata allo schema.
  2. Tutti integrati o definiti dall'utente funzioni chiamate dall'utente definito le funzioni sono deterministiche.
  3. Il corpo dei riferimenti alle funzioni nessun oggetto di database al di fuori di ambito della funzione. Per esempio, una funzione deterministica non può tabelle di riferimento diverse dalla tabella variabili locali per il la funzione.
  4. La funzione non chiama nessuna estese procedure archiviate.

Le funzioni definite dall'utente che non soddisfano questi criteri sono contrassegnate come non deterministiche. Le funzioni non deterministiche integrate non sono consentite nel corpo delle funzioni definite dall'utente.

Prova questo:

CAST(FLOOR(CAST([datetime_column] as FLOAT)) AS DateTime)

Dovrebbe andare molto più veloce dell'opzione CONVERT.

Ecco la mia migliore risposta a rispondere alla domanda originale:

Prova questo:

/* create a deterministic schema bound function */
CREATE FUNCTION FloorDate(@dt datetime)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN 
    RETURN CONVERT(datetime,  FLOOR(CONVERT(float, @dt)))
END
GO

Per provare, provare quanto segue. Si prega di notare l'uso di " PERSISTED " per la colonna calcolata e l'uso di [dbo.] quando si fa riferimento alla funzione

/*create a test table */
CREATE TABLE [dbo].[TableTestFloorDate](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [TestDate] [datetime] NOT NULL,
    [TestFloorDate]  AS ([dbo].[FloorDate]([TestDate])) PERSISTED,
 CONSTRAINT [PK_TableTestFloorDate] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
) 

Ora dovresti essere in grado di aggiungere un indice sulla colonna calcolata (ma vedi più tardi)

CREATE INDEX IX_TestFloorDate ON  [dbo].[TableTestFloorDate](TestFloorDate)

Inserisci alcuni dati casuali tutte le volte che vuoi ma più (1000+) è meglio se desideri testare i piani di utilizzo / esecuzione dell'indice

INSERT INTO TableTestFloorDate (TestDate) VALUES( convert(datetime, RAND()*50000))

Ottieni i risultati

SELECT * FROM TableTestFloorDate WHERE TestFloorDate='2013-2-2'

Ora ecco il GOTCHA ... L'indice che è stato creato sulla colonna calcolata non viene utilizzato! Invece, anche quando si selezionano i dati sul campo persistente TestFloorDate, SQLServer (o almeno la mia versione) preferisce un indice su TestDate.

CREATE INDEX IX_TestFloorDate ON  [dbo].[TableTestFloorDate](TestDate)

Sono abbastanza sicuro (dalla memoria) che gli indici su colonne calcolate e persistenti sono di beneficio dal punto di vista delle prestazioni - immagino che dovrai solo provare / testare i tuoi usi specifici

(Spero di averti aiutato!)

Suggerirei un po 'più semplice:

 cast(cast([datetime_column] as int) as datetime)

ma sospetto che incontrerai lo stesso problema.

Ora, se il problema riguarda il cast di tornare a un datetime, potresti prendere in considerazione l'utilizzo del solo cast ([datetime_column] come int) come campo separato, solo per l'indice.

Guarda quella domanda che ha posto e risposto di Cade Roux . Forse la soluzione sarebbe quella di creare una funzione utilizzando WITH SCHEMABINDING e quindi utilizzarla nella colonna calcolata

Modifica

Capisco che il tuo obiettivo è quello di poter avere un indice su quella colonna.

Se ciò non può essere fatto con una colonna calcolata, forse l'unica opzione sarebbe quella di creare una colonna ordinaria e modificare i dati in quella colonna ogni volta che aggiorni quella su cui si basa. (dire in trigger)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top