Creación de índice en campo calculado: la cadena o los datos binarios se truncarían


8

Tengo una tabla Foocon los siguientes campos:

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

Ahora quiero crear un índice en LongValue, para poder buscar fácilmente valores serializados que representen números.

create nonclustered index IX_Foo on Foo(LongValue);

Lo que escupe el siguiente error:

Cadena o datos binarios podrían truncarse.

Sí, hay datos existentes en SerializedValue. Pero, ¿qué se puede truncar creando un índice en un campo calculado?

Respuestas:


8

El error no es causado por la creación del índice. El error se produce TRY_CASTcuando los valores de columna calculados se evalúan en la creación del índice.

Si ejecuto esto:

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

Me sale el mismo error.

La documentación dice (énfasis mío):

Si la conversión tiene éxito, TRY_CAST devuelve el valor como el tipo de datos especificado; Si se produce un error, se devuelve un valor nulo. Sin embargo, si solicita una conversión que no está explícitamente permitida, TRY_CAST falla con un error.

Ahora, no está exactamente claro en qué casos fallará con un error (parece un poco tonto dado el punto completo de la función, pero de todos modos ...), por lo que podemos arreglar el código transformando los valores de entrada (use algo razonable para los datos en su tabla), ya que no hay necesidad de procesar una cadena enorme cuando no cabe en un bigint de todos modos:

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

Esto regresa NULLya que el valor no es válido, pero no bombardea con un error.


-1

Si tiene una cadena con un valor que es demasiado largo, la creación del índice fallará. Intenté un pequeño código de prueba con 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

Mi experimento rápido mostró que el código funciona siempre y cuando el valor nvarchar (max) sea de 4000 caracteres o menos. (Por supuesto, todos los espacios en blanco sin nada al final se contraen y no tienen caracteres y, por lo tanto, funcionan bien). El carácter 4001 activa el String or binary data would be truncatedmensaje. Por lo tanto, puede examinar sus datos para un SerializedValue que tenga más de 4000 caracteres.

EDITAR: Sí, la conversión es a BIGINT. El problema no es el BIGINT, sino el NVARCHAR(MAX). Por ejemplo:

  1. Si una fila contiene '1111111111111111111', ambos CREATE INDEXconvertirán el valor a BIGINT.
  2. Si una fila es de 0 a 4000 '1, puede CREATE INDEX, pero el valor puede ser NULLporque se desborda BIGINT.
  3. Si una fila tiene más de 4000 caracteres, entonces CREATE INDEXfalla.

Entonces, parece que el contenido real de NVARCHAR (MAX) es lo que importa para CREATE INDEX.

EDITAR: Jon Seigel identificó que TRY_CAST desencadena la falla en el índice de creación cuando la cadena es más larga que nvarchar (4000).


2
Esto realmente no responde la pregunta. El índice está en un bigint. Nunca será otra cosa que un bigint. La pregunta es por qué los datos se truncarían cuando un bigint está dentro del
límite de

1
@MarkSinkinson Editado para proporcionar más detalles. El problema es el contenido de NVARCHAR (MAX).
RLF
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.