Apakah ada fungsi bawaan (tersembunyi) di MS-SQL untuk tanda kutip nama objek?

12

Terkadang saya menyimpan nama objek (pengidentifikasi) di beberapa database kami, misalnya dalam beberapa tabel parameter. Karena saya memilih catatan dari tabel ini menggunakan operator perbandingan '=' atau 'LIKE', saya harus berhati-hati untuk menyimpan nama-nama ini selalu dengan atau tanpa tanda kurung .

IF EXISTS (SELECT 1 FROM MYTABLE WHERE OBJ_NAME = '[TABLE_NAME]';

atau

IF EXISTS (SELECT 1 FROM MYTABLE WHERE OBJ_NAME = 'TABLE_NAME';

Namun MS-SQL memiliki beberapa fungsi di mana Anda dapat menggunakan nama objek dengan atau tanpa tanda kurung, misalnya fungsi OBJECT_ID (). Saya telah membuat contoh minimal di dbfiddle.uk .

CREATE TABLE TEST
(
    ID     INT IDENTITY(1,1) PRIMARY KEY,
    OBJECT sysname NOT NULL
);
GO

INSERT INTO TEST VALUES ('[obj1]'),('obj2'),('obj3'),('[obj4]');
GO

Sekarang saya dapat menggunakan OBJECT_ID () untuk memeriksa apakah tabel TEST ada dengan cara ini:

IF OBJECT_ID('TEST') IS NOT NULL
BEGIN
    SELECT 'TEST EXISTS.' OBJECT_ID;
END
GO

| OBJECT_ID    |
| :----------- |
| TEST EXISTS. |

IF OBJECT_ID('[TEST]') IS NOT NULL
BEGIN
    SELECT '[TEST] EXISTS.' OBJECT_ID;
END
GO

| OBJECT_ID      |
| :------------- |
| [TEST] EXISTS. |

Tidak masalah jika saya lulus TEST pengidentifikasi dengan atau tanpa tanda kurung, parser cukup pintar untuk menghapus tanda kurung.

Yah, saya bisa mensimulasikan ini dengan menambahkan fungsi skalar yang menghapus tanda kurung dari satu string:

CREATE FUNCTION UNQUOTENAME(@TXT NVARCHAR(MAX)) 
RETURNS NVARCHAR(MAX)
AS
    BEGIN
        RETURN IIF(LEFT(@TXT, 1) = N'[' AND RIGHT(@TXT, 1) = N']', 
                   SUBSTRING(@TXT, 2, LEN(@TXT) -  2), 
                   @TXT);
    END;
GO

Dan kemudian gunakan dengan cara ini:

SELECT dbo.UNQUOTENAME (N'[FIELD]') NAME1, N'FIELD' NAME2;
GO

NAME1 | NAME2
:---- | :----
FIELD | FIELD

SELECT ID, OBJECT 
FROM   TEST 
WHERE OBJECT LIKE 'obj%';
GO

ID | OBJECT
-: | :-----
 2 | obj2  
 3 | obj3  

SELECT ID, dbo.UNQUOTENAME(OBJECT) 
FROM   TEST 
WHERE  dbo.UNQUOTENAME(OBJECT) LIKE 'obj%';
GO

ID | (No column name)
-: | :---------------
 1 | obj1
 2 | obj2
 3 | obj3
 4 | obj4  

Tapi pertanyaan saya adalah:

  • Apakah ada fungsi bawaan tersembunyi yang menghilangkan tanda kurung menggunakan T-SQL?

Aku di sini

McNets
sumber

Jawaban:

12

Apakah ada fungsi bawaan tersembunyi yang menghilangkan tanda kurung menggunakan T-SQL?

Tidak , tidak menggunakan T-SQL.

OBJECT_IDadalah fungsi intrinsik . Ini diimplementasikan secara langsung dalam kode dieksekusi SQL Server, bukan dalam T-SQL; dan itu tidak memanggil T-SQL saat dipanggil.

Saat runtime, id objek diperoleh melalui pemanggilan layanan ekspresi sqlmin!I4ObjIdWstr.

Implementasi kemudian melewati semua langkah yang diperlukan untuk menyelesaikan parameter string yang disediakan (s) ke id objek dalam database yang dirujuk.

Salah satu langkah pertama termasuk berurusan dengan pengidentifikasi terbatas dalam string melalui sqlmin!CbParseQuotesW. Dalam arti sempit, itu adalah fungsi kode yang Anda maksud, tetapi tidak dapat diakses langsung dari T-SQL. Ini berisi kode berikut:

cmp     r9d,22h
je      sqlmin!CbParseQuotesW+0x185
cmp     r9d,2Eh
je      sqlmin!CbParseQuotesW+0x139
cmp     r9d,5Bh
je      sqlmin!CbParseQuotesW+0xfe
cmp     r9d,5Dh
je      sqlmin!CbParseQuotesW+0xda

... yang merupakan tes untuk menangani karakter:

  • hex 22 = dec 34 = "
  • hex 2E = dec 46 = .
  • hex 5B = dec 91 = [
  • hex 5D = dec 93 = ]

Sisa proses untuk menyelesaikan parameter ke id melibatkan:

  • Memulai transaksi read-only otomatis
  • Memeriksa persyaratan basis data yang terkandung
  • Iterasi melalui kemungkinan kecocokan untuk parameter nama (menggunakan susunan yang benar)
    • Dalam nama basis data yang disediakan (atau basis data konteks saat ini)
    • Dalam nama skema yang disediakan (atau sistem , atau skema default pengguna, dll.)
  • Mengambil kunci metadata yang diperlukan
  • Konsultasi cache metadata untuk pertandingan
  • Mengambil metadata ke dalam cache jika perlu
  • Memeriksa izin (untuk mengakses id objek)
  • Mengembalikan id dari objek yang cocok pertama (jika ada)

Di samping catatan, kode dalam pertanyaan:

IF OBJECT_ID('TEST') IS NOT NULL

... tidak hanya mencari tabel. Untuk itu akan perlu menggunakan parameter fungsi kedua. Selain itu, hanya mencari setiap objek bernama UJI skema-scoped - sehingga tampilan bernama BananaSchema.TEST akan cocok, misalnya. Ekspresi yang lebih baik adalah:

IF OBJECT_ID(N'dbo.TEST', N'U') IS NOT NULL

Tanya Jawab terkait:

Paul White 9
sumber
18

Terkadang saya menyimpan nama objek di beberapa database kami

Saya harus berhati-hati untuk menyimpan nama ini selalu dengan atau tanpa tanda kurung.

"Nama objek" secara teknis disebut pengidentifikasi . Dalam beberapa konteks, pengidentifikasi akan muncul kode TSQL dikelilingi oleh [dan] atau "dan". Karakter-karakter ini bukan bagian dari pengidentifikasi, dan Anda tidak boleh menyimpannya.

Sebaliknya simpan pengenal sebagai nvarchar (128) (atau sysname), dan tambahkan pembatas saat runtime menggunakan fungsi QUOTENAME .

Kebalikan dari QUOTENAME adalah PARSENAME , yang memiliki kemampuan tambahan untuk menavigasi nama multi-bagian.

Perhatikan bahwa QUOTENAME memiliki parameter kedua opsional, dan jika Anda menentukan karakter kutipan tunggal untuk parameter itu, QUOTENAME tidak membuat ekspresi pengidentifikasi terbatas yang valid. Ini memancarkan ekspresi literal varchar.

David Browne - Microsoft
sumber
7

SQL Server jelas memiliki sesuatu internal yang dihapus [square brackets](atau pengidentifikasi lainnya, seperti "double quotes").

Ketika Anda membuat tabel seperti [dbo].[foo], Anda benar, hanya fooakan disimpan di sys.tablesdan sys.objects, dan tidak ada keluhan bahwa skema [dbo](dengan tanda kurung siku) tidak ditemukan.

Tetapi ini terjadi di dalam kode CREATE TABLE. Mereka mungkin menggunakan PARSENAME(), seperti yang ditunjukkan David. Menghubungkan debugger bisa menunjukkan dengan pasti, tetapi apakah itu penting?

Anda dapat mencari di tempat lain untuk melihat apa yang mereka lakukan, dan sys.sp_renamepada kenyataannya memang menghasilkan yang PARSENAME()digunakan:

select @UnqualOldName = parsename(@objname, 1),
        @QualName1 = parsename(@objname, 2),
        @QualName2 = parsename(@objname, 3),
        @QualName3 = parsename(@objname, 4)

Tapi sekali lagi, saya tidak yakin saya mengerti mengapa Anda hanya ingin kadang-kadang menghapus tanda kurung.

Bagi saya, secara pribadi, sebagian besar kode saya ditulis untuk audiens yang lebih luas, yang akan menggunakan kode di lingkungan di mana saya tidak memiliki pengetahuan atau kontrol atas apakah mereka menggunakan pengidentifikasi yang tidak aman. Jadi saya selalu dan akan selalu menulis (dan lebih suka) kode yang digunakan QUOTENAME()untuk menghasilkan skrip yang mencakup segala jenis pengidentifikasi.

Saya lebih suka memiliki tanda kurung siku di sana sepanjang waktu, daripada membawanya pergi dan digigit pada saat dibutuhkan.

Aaron Bertrand
sumber
2
@ McNets - Untuk jumlah kasus yang sangat kecil di mana ini bisa berguna saya lebih suka mereka fokus pada hal-hal lain. Anda dapat dengan mudah menggunakan fungsi string yang ada untuk menanggalkan posisi awal [dan akhir ]serta menggantikannya ]]dengan]
Martin Smith
-6

Ketika tanda kurung diperlukan - itu karena pengidentifikasi Anda sudah merupakan kata kunci yang dipesan. Menggunakannya secara sewenang-wenang tidak hanya tidak perlu, itu menyebabkan banyak kebingungan seperti yang Anda lihat.

Menurut pendapat saya, cara terbaik adalah menghindari menggunakan pengidentifikasi yang dipesan di tempat pertama.

jinzai
sumber