2008-11-21 5 views
6

(. Это связано с Floor a date in SQL server)SQL Server: пол дата в сервере SQL, но при этом оставаться детерминированным

Существует ли детерминированным выражение полу Задан? Когда я использую это как формула вычисленного столбца:

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

я получаю сообщение об ошибке, когда я помещаю индекс по этому столбцу:

Невозможно создать индекс, так как ключевой столбец «EffectiveDate» является не- детерминированным или неточным.

Но оба DATEDIFF и DATEADD являются детерминированными функциями по определению. Где поймать? Является ли это возможным?

ответ

3

Я предполагаю, что это какая-то ошибка. В SQL 2005 я смог создать такое индексированное представление без проблем (код ниже). Когда я попытался запустить его на SQL 2000, я получил ту же ошибку, что и вы.

Следующее, похоже, работает на SQL 2000, но я получаю предупреждение о том, что индекс будет проигнорирован, и вам придется конвертировать каждый раз, когда вы выбрали из представления.

CONVERT(CHAR(8), datetime_column, 112) 

Работает в 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 
2

У вашей колонки [datetime_column] установлено значение по умолчанию, равное «getDate()»?

Если это так, так как функция GETDATE() недетерминирован, это вызовет эту ошибку ...

Является ли определенная пользователем функция является детерминированной или недетерминированной зависит от того, как закодирована функция. Определяемые пользователем функции детерминированы, если:

  1. Функция связана с схемой.
  2. Все встроенные или определенные пользователем функции , вызываемые определяемой пользователем функцией , являются детерминированными.
  3. Тела функций ссылки Нет объектов базы данных за пределами Объем функции. Например, детерминированная функция не может ссылочные таблицы, отличные от таблицы переменных, которые являются локальными для функции .
  4. Функция не вызывает никаких дополнительных хранимых процедур .

Определенные пользователем функции, которые не соответствуют этим критериям, обозначены как недетерминированные. Встроенные недетерминированные функции не допускаются в тело пользовательских функций.

+0

Да, это так. Но откуда эта ошибка? – Tomalak 2008-11-21 17:30:39

+0

getDate не является детерминированным. Я считаю, что это было бы причиной – kristof 2008-11-21 17:32:56

+0

Да, вот почему! – 2008-11-21 17:36:32

1

Попробуйте это:

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

Это должно пойти гораздо быстрее, чем вариант CONVERT.

0

Посмотрите на that question asked and answered by Cade Roux. Возможно, решение было бы создать функцию, используя С SCHEMABINDING, а затем использовать его в вычисляемого столбца

EDIT

Я понимаю, что вы цель состоит в том, чтобы быть в состоянии иметь индекс по этому столбцу.

Если это невозможно сделать с вычисленным столбцом, возможно, единственным вариантом будет создание обычного столбца и изменение данных в этом столбце при каждом обновлении, на котором оно основано.(Скажем, в триггере)

0

Я предлагаю Несколько проще:

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

, но я подозреваю, что вы будете работать с той же проблемой.

Теперь, если проблема заключается в возвращении к дате времени, вам может потребоваться использовать только cast([datetime_column] as int) в качестве отдельного поля, только для индекса.

1

Вот мой лучший ответ ответить на исходный вопрос:

Попробуйте это:

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

Чтобы проверить, попробуйте следующее. Пожалуйста, обратите внимание на использование «PERSISTED» для вычисляемого столбца и использования [DBO.] При обращении к функции

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

Теперь вы должны иметь возможность добавлять индекс по вычисляемого столбца (но см Гоча позже)

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

Вставьте некоторые случайные данные, как столько раз, сколько вы хотите, но более (1000+) лучше, если вы хотите, чтобы проверить использование индекса/выполнение планов

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

Получить результаты

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

Теперь вот Гоча ... индекс, который был создан на вычисляемого столбца не используется! Вместо этого, даже при выборе данных в сохраняемом поле TestFloorDate, SQLServer (или, по крайней мере, моя версия) предпочитает индекс TestDate.

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

Я довольно уверен (из памяти), что индексы по вычислено, сохранялись столбцы имеют преимущество с точки зрения производительности - Я думаю, вы просто должны попробовать/тест для своих конкретных использований

(Надеюсь, я помог!)