Создание индекса для вычисляемого поля: строка или двоичные данные будут обрезаны

8

У меня есть таблица Fooсо следующими полями:

ID bigint not null identity(1,1),
SerializedValue nvarchar(max),
LongValue as TRY_CAST(SerializedValue as bigint)

Теперь я хочу создать индекс для LongValue, чтобы я мог легко найти сериализованные значения, которые представляют числа.

create nonclustered index IX_Foo on Foo(LongValue);

Который выкладывает на меня следующую ошибку:

Строка или двоичные данные будут проигнорированы.

Да, в SerializedValue есть данные. Но что, молиться, можно укоротить, создав индекс на вычисляемом поле?

Шауль Бер
источник

Ответы:

8

Ошибка не вызвана созданием индекса. Ошибка вызвана тем, TRY_CASTчто вычисленные значения столбца оцениваются при создании индекса.

Если я запускаю это:

SELECT TRY_CAST(REPLICATE(CONVERT(nvarchar(MAX), N'a'), 4001) AS bigint)

Я получаю ту же ошибку.

В документации сказано (выделено мое):

Если приведение выполнено успешно, TRY_CAST возвращает значение в качестве указанного data_type; если происходит ошибка, возвращается ноль. Однако, если вы запрашиваете преобразование, которое явно не разрешено, TRY_CAST завершается с ошибкой.

Теперь не совсем ясно, в каких случаях это приведет к ошибке с ошибкой (кажется, что-то вроде асинина, учитывая весь смысл функции, но в любом случае ...), поэтому мы можем исправить код, преобразовав входные значения (использовать что-то разумно для данных в вашей таблице), поскольку нет необходимости обрабатывать огромную строку, когда она все равно не помещается в bigint:

SELECT TRY_CAST(LEFT(REPLICATE(CONVERT(nvarchar(MAX), N'1'), 4001), 100) AS bigint)

Возвращается, так NULLкак значение недопустимо, но не выдает ошибку.

Джон Сайгель
источник
-1

Если у вас есть строка со слишком длинным значением, создание индекса завершится неудачно. Я попробовал небольшой тестовый код с использованием SQL Server 2012.

CREATE TABLE dbo.foo 
(ID bigint not null identity(1,1),
SerializedValue nvarchar(max),
LongValue as TRY_CAST(SerializedValue as bigint));

INSERT INTO dbo.foo (serializedvalue) VALUES(REPLICATE(' ', 4000)+'1');

CREATE INDEX GotToTry ON foo(LongValue);

DROP TABLE dbo.foo;
GO

Мой быстрый эксперимент показал, что код работает до тех пор, пока значение nvarchar (max) составляет 4000 символов или менее. (Конечно, все пробелы, в конце которых ничего не написано, сворачиваются без символов и, таким образом, работают просто отлично.) 4001-й символ вызывает String or binary data would be truncatedсообщение. Таким образом, вы можете проверить свои данные на предмет SerializedValue длиной более 4000 символов.

РЕДАКТИРОВАТЬ: Да, преобразование в BIGINT. Проблема не в BIGINT, а в NVARCHAR(MAX). Например:

  1. Если строка содержит «1111111111111111111», она будет CREATE INDEXи преобразовать значение в BIGINT.
  2. Если строка имеет значение от 0 до 4000 '1, это возможно CREATE INDEX, но значение может быть, NULLпоскольку она переполняется BIGINT.
  3. Если строка длиннее 4000 символов, CREATE INDEXпроизойдет сбой.

Таким образом, похоже, что фактическое содержание NVARCHAR (MAX) имеет значение для CREATE INDEX.

РЕДАКТИРОВАТЬ: Джон Зигель определил, что TRY_CAST вызывает сбой при создании индекса, когда строка длиннее, чем nvarchar (4000).

ДКП
источник
2
Это на самом деле не отвечает на вопрос. Индекс находится на bigint. Это никогда не будет чем-то другим, кроме bigint. Вопрос в том, почему данные должны быть усечены, когда bigint находится в пределах допустимого размера индекса
Марк Синкинсон,
1
@MarkSinkinson Отредактировано, чтобы предоставить более подробную информацию. Проблема заключается в содержимом NVARCHAR (MAX).
RLF