Pregunta

(Esto está relacionado con Establecer una fecha en el servidor SQL ).

¿Existe una expresión determinista para colocar un DATETIME? Cuando uso esto como una fórmula de columna calculada:

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

aparece un error cuando coloco un índice en esa columna:

  

No se puede crear el índice porque la columna clave 'EffectiveDate' no es determinista o imprecisa.

Pero tanto DATEDIFF como DATEADD son funciones deterministas por definición. ¿Dónde está la trampa? ¿Es posible?

¿Fue útil?

Solución

Supongo que esto es un error de algún tipo. En SQL 2005 pude crear una vista indexada sin problemas (el código está debajo). Cuando intenté ejecutarlo en SQL 2000, recibí el mismo error que usted está obteniendo.

Lo siguiente parece funcionar en SQL 2000, pero recibo una advertencia de que el índice será ignorado Y que tendría que realizar la conversión cada vez que seleccionara de la vista.

CONVERT(CHAR(8), datetime_column, 112)

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

Otros consejos

¿Su columna [datetime_column] tiene un valor predeterminado establecido en " getDate () " ??

Si es así, dado que la función getdate () no es determinista, esto causará este error ...

Si una función definida por el usuario es determinista o no depende de cómo se codifica la función. Las funciones definidas por el usuario son deterministas si:

  1. La función está vinculada al esquema.
  2. Todo incorporado o definido por el usuario funciones llamadas por el definido por el usuario la función es determinista.
  3. El cuerpo de las referencias de funciones sin objetos de base de datos fuera del Alcance de la función. Por ejemplo, una función determinista no puede tablas de referencia distintas de la tabla variables que son locales a la función.
  4. La función no llama a ninguna procedimientos almacenados extendidos.

Las funciones definidas por el usuario que no cumplen con estos criterios están marcadas como no deterministas. Las funciones no deterministas integradas no están permitidas en el cuerpo de las funciones definidas por el usuario.

Prueba esto:

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

Debería ir mucho más rápido que la opción CONVERTIR.

Aquí está mi mejor respuesta para responder la pregunta original:

Prueba esto:

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

Para probar, intente lo siguiente. Tenga en cuenta el uso de " PERSISTED " para la columna calculada y el uso de [dbo.] al referirse a la función

/*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) 
) 

Ahora debería poder agregar un índice en la columna calculada (pero vea gotcha más adelante)

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

Inserte algunos datos aleatorios tantas veces como desee, pero más (1000+) es mejor si desea probar el uso del índice / planes de ejecución

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

Obtenga los resultados

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

Ahora aquí está el GOTCHA ... ¡El índice que se ha creado en la columna calculada no se utiliza! En cambio, incluso al seleccionar datos en el campo persistente TestFloorDate, SQLServer (o al menos mi versión) prefiere un índice en TestDate.

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

Estoy bastante seguro (desde la memoria) de que los índices en columnas calculadas y persistentes son beneficiosos desde una perspectiva de rendimiento; supongo que solo tendrá que probar / probar sus propios usos específicos

(¡Espero haber ayudado!)

Sugeriría algo más simple:

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

pero sospecho que se encontrará con el mismo problema.

Ahora, si el problema está en volver a una fecha y hora, puede considerar usar solo cast ([datetime_column] como int) como un campo separado, solo para el índice.

Mire esa pregunta se hizo y respondió por Cade Roux . Quizás la solución sería crear una función usando WITH SCHEMABINDING y luego usarla en la columna calculada

EDIT

Entiendo que su objetivo es poder tener un índice en esa columna.

Si eso no se puede hacer con una columna calculada, entonces quizás la única opción sería crear una columna ordinaria y modificar los datos en esa columna cada vez que actualice la columna en la que se basa. (digamos en el disparador)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top