SQL Server: укажите дату на SQL-сервере, но оставайтесь детерминированными - PullRequest
6 голосов
/ 21 ноября 2008

(Это связано с Пол даты на сервере SQL .)

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

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

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

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

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

Ответы [ 6 ]

3 голосов
/ 21 ноября 2008

Я предполагаю, что это какая-то ошибка. В 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 голосов
/ 21 ноября 2008

Есть ли в вашем столбце [datetime_column] значение по умолчанию, установленное на "getDate ()" ??

Если это так, поскольку функция getdate () является недетерминированной, это приведет к этой ошибке ...

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

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

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

1 голос
/ 24 июля 2013

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

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

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

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

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

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

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

1 голос
/ 21 ноября 2008

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

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

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

0 голосов
/ 21 ноября 2008

Я бы предложил несколько проще:

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

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

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

0 голосов
/ 21 ноября 2008

Посмотрите на на этот вопрос, заданный и получивший ответ от Cade Roux . Возможно, решением было бы создать функцию с помощью WITH SCHEMABINDING, а затем использовать ее в вычисляемом столбце

EDIT

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

Если это невозможно сделать с вычисляемым столбцом, то, возможно, единственный вариант - создать обычный столбец и изменять данные в этом столбце каждый раз, когда вы обновляете тот, на котором он основан. (скажем, в триггере)

...