Creazione dell'indice sul campo calcolato: i dati stringa o binari verrebbero troncati


8

Ho una tabella Foocon i seguenti campi:

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

Ora voglio creare un indice su LongValue, in modo da poter cercare facilmente i valori serializzati che rappresentano i numeri.

create nonclustered index IX_Foo on Foo(LongValue);

Il che mi sporge il seguente errore:

I dati stringa o binari verrebbero troncati.

Sì, ci sono dati esistenti in SerializedValue. Ma cosa, per favore, può essere troncato creando un indice su un campo calcolato?

Risposte:


8

L'errore non è causato dalla creazione dell'indice. L'errore è causato da TRY_CASTquando i valori di colonna calcolati vengono valutati durante la creazione dell'indice.

Se eseguo questo:

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

Ho fatto lo stesso errore.

La documentazione dice (enfasi sulla mia):

Se il cast ha esito positivo, TRY_CAST restituisce il valore come tipo di dati specificato; se si verifica un errore, viene restituito null. Tuttavia, se richiedi una conversione esplicitamente non consentita, TRY_CAST ha esito negativo con un errore.

Ora, non è esattamente chiaro in quali casi fallirà con un errore (sembra un po 'asinino dato l'intero punto della funzione, ma comunque ...), quindi possiamo sistemare il codice trasformando i valori di input (usa qualcosa ragionevole per i dati nella tabella), poiché non è necessario elaborare una stringa enorme quando non si adatta comunque a un bigint:

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

Questo ritorna NULLpoiché il valore non è valido, ma non bombarda con un errore.


-1

Se si dispone di una stringa con un valore troppo lungo, la creazione dell'indice avrà esito negativo. Ho provato un piccolo codice di prova utilizzando 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

Il mio rapido esperimento ha dimostrato che il codice funziona fintanto che il valore nvarchar (max) è di 4000 caratteri o meno. (Ovviamente, tutti gli spazi vuoti senza nulla alla fine non si riducono a nessun carattere e quindi funzionano perfettamente.) Il 4001 ° carattere attiva il String or binary data would be truncatedmessaggio. Quindi potresti esaminare i tuoi dati per un valore seriale più lungo di 4000 caratteri.

EDIT: Sì, la conversione è in a BIGINT. Il problema non è il BIGINT, ma è il NVARCHAR(MAX). Per esempio:

  1. Se una riga contiene "1111111111111111111", entrambe CREATE INDEXconvertiranno il valore in BIGINT.
  2. Se una riga è compresa tra 0 e 4000 '1, può CREATE INDEX, ma il valore potrebbe essere NULLpoiché trabocca BIGINT.
  3. Se una riga è più lunga di 4000 caratteri, allora CREATE INDEXnon riesce.

Quindi, sembra che i contenuti effettivi di NVARCHAR (MAX) siano importanti per CREATE INDEX.

EDIT: Jon Seigel ha identificato che TRY_CAST innesca l'errore nel creare indice quando la stringa è più lunga di nvarchar (4000).


2
Questo non risponde davvero alla domanda. L'indice è su un bigint. Non sarà mai altro che un bigint. La domanda è: perché i dati verrebbero troncati quando un bigint rientra nei limiti delle dimensioni di un indice
Mark Sinkinson,

1
@MarkSinkinson Modificato per fornire maggiori dettagli. Il problema sono i contenuti di NVARCHAR (MAX).
RLF,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.