Membuat indeks pada bidang yang dihitung: data string atau biner akan terpotong

8

Saya punya tabel Foodengan bidang-bidang berikut:

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

Sekarang saya ingin membuat indeks pada LongValue, sehingga saya dapat dengan mudah mencari nilai-nilai serial yang mewakili angka.

create nonclustered index IX_Foo on Foo(LongValue);

Yang memuntahkan kesalahan berikut pada saya:

Data string atau biner akan terpotong.

Ya, ada data yang ada di SerializedValue. Tapi apa, berdoa, dapat dipotong dengan membuat indeks pada bidang yang dihitung?

Shaul Behr
sumber

Jawaban:

8

Kesalahan tidak disebabkan oleh pembuatan indeks. Kesalahan ini disebabkan oleh TRY_CASTketika nilai kolom yang dihitung dievaluasi pada pembuatan indeks.

Jika saya menjalankan ini:

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

Saya mendapatkan kesalahan yang sama.

The dokumentasi mengatakan (penekanan):

Jika para pemeran berhasil, TRY_CAST mengembalikan nilai sebagai tipe data_t yang ditentukan; jika kesalahan terjadi, null dikembalikan. Namun jika Anda meminta konversi yang secara eksplisit tidak diizinkan, maka TRY_CAST gagal dengan kesalahan.

Sekarang, tidak terlalu jelas dalam kasus mana ia akan gagal dengan kesalahan (sepertinya agak bodoh mengingat seluruh titik fungsi, tapi tetap ...), jadi kita dapat memperbaiki kode dengan mengubah nilai input (menggunakan sesuatu masuk akal untuk data dalam tabel Anda), karena tidak perlu memproses string besar ketika itu tidak akan cocok dengan bigint:

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

Ini kembali NULLkarena nilainya tidak valid, tetapi tidak meledak dengan kesalahan.

Jon Seigel
sumber
-1

Jika Anda memiliki string dengan nilai yang terlalu panjang, maka pembuatan indeks akan gagal. Saya mencoba kode uji kecil menggunakan 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

Eksperimen cepat saya menunjukkan bahwa kode berfungsi selama nilai nvarchar (maks) adalah 4000 karakter atau kurang. (Tentu saja, semua kosong tanpa apa-apa pada akhirnya runtuh tanpa karakter dan dengan demikian berfungsi dengan baik.) Karakter 4001 memicu String or binary data would be truncatedpesan. Jadi, Anda dapat memeriksa data Anda untuk Nilai Serialized yang lebih dari 4000 karakter.

EDIT: Ya, konversi ke a BIGINT. Masalahnya bukan BIGINT, tetapi adalah NVARCHAR(MAX). Sebagai contoh:

  1. Jika satu baris berisi '1111111111111111111', maka keduanya akan CREATE INDEXdan mengonversi nilainya menjadi BIGINT.
  2. Jika satu baris adalah 0 hingga 4000 '1, itu bisa CREATE INDEX, tetapi nilainya mungkin NULLkarena melimpah BIGINT.
  3. Jika satu baris lebih panjang dari 4000 karakter, maka CREATE INDEXgagal.

Jadi, sepertinya isi sebenarnya dari NVARCHAR (MAX) adalah yang penting bagi CREATE INDEX.

EDIT: Jon Seigel mengidentifikasi bahwa TRY_CAST memicu kegagalan membuat indeks ketika string lebih panjang dari nvarchar (4000).

RLF
sumber
2
Ini tidak benar-benar menjawab pertanyaan. Indeks berada di bigint. Tidak akan pernah ada yang lain selain bigint. Pertanyaannya adalah mengapa data akan terpotong ketika bigint berada dalam batas kelonggaran indeks
Mark Sinkinson
1
@MarkSinkinson Diedit untuk memberikan detail lebih lanjut. Masalahnya adalah konten NVARCHAR (MAX).
RLF