(Это связано с Напишите дату на SQL сервере.)
Существует ли детерминированное выражение для определения DATETIME? Когда я использую это как формулу вычисляемого столбца:
DATEADD(dd, DATEDIFF(dd, 0, [datetime_column]), 0)
когда я помещаю индекс в этот столбец, я получаю сообщение об ошибке:
Cannot create index because the key column 'EffectiveDate' is non-deterministic or imprecise.
Но и DATEDIFF, и DATEADD по определению являются детерминированными функциями. Где подвох? Является ли это возможным?


Ваш столбец [datetime_column] имеет значение по умолчанию, установленное на "getDate ()" ??
Если это так, поскольку функция getdate () не является детерминированной, это вызовет эту ошибку ...
Детерминированная или недетерминированная функция, определяемая пользователем, зависит от того, как функция кодируется. Пользовательские функции являются детерминированными, если:
Пользовательские функции, не соответствующие этим критериям, помечаются как недетерминированные. Встроенные недетерминированные функции не допускаются в теле пользовательских функций.
Но это просто значение по умолчанию. Это не часть формулы. Кстати, я получаю ту же ошибку для столбца NULL по умолчанию.
Я предполагаю, что подпрограмма, которая делает это, не различает ту часть определения столбца, которая представляет формулу, и часть, которая представляет значение по умолчанию ...
Да, это так. Я пробовал предложение Кристофа.
Попробуй это:
CAST(FLOOR(CAST([datetime_column] as FLOAT)) AS DateTime)
Это должно происходить намного быстрее, чем опция ПРЕОБРАЗОВАТЬ.
CAST не является детерминированным для значений даты и времени.
Посмотрите на на этот вопрос задал и ответил Кейд Ру. Возможно, решением было бы создать функцию с использованием WITH SCHEMABINDING, а затем использовать ее в вычисляемом столбце
РЕДАКТИРОВАТЬ
Я понимаю, что ваша цель - иметь индекс для этого столбца.
Если это невозможно сделать с вычисляемым столбцом, то, возможно, единственным вариантом будет создание обычного столбца и изменение данных в этом столбце каждый раз, когда вы обновляете столбец, на котором он основан. (сказать в триггере)
Я бы предложил несколько попроще:
cast(cast([datetime_column] as int) as datetime)
но я подозреваю, что вы столкнетесь с той же проблемой.
Теперь, если проблема заключается в возврате к дате и времени, вы можете рассмотреть возможность использования только cast([datetime_column] as int) в качестве отдельного поля, только для индекса.
Проблема также связана с приведением из datetime (или convert () ing, если на то пошло).
Я предполагаю, что это своего рода ошибка. В 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
Вот мой лучший ответ на исходный вопрос:
Попробуй это:
/* 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)
Я почти уверен (по памяти), что индексы для вычисляемых постоянных столбцов имеют преимущество с точки зрения производительности - я думаю, вам просто нужно попробовать / протестировать для ваших собственных конкретных применений
(Надеюсь, я помог!)
У меня нет возможности проверить это прямо сейчас. Совместим ли этот SQL Server 2000 (я знаю, что он старый, но теги в вопросе указывали на эту версию)?
Вышеупомянутое было протестировано в Sql2012, но по памяти я не понимаю, почему это не работает на Sql2k точно так, как описано выше.
getDate недетерминирован, я считаю, что это может быть причиной