MS-SQL'de nesne adlarını ayırmak için herhangi bir (gizli) yerleşik işlev var mı?


12

Bazen nesne adlarını (tanımlayıcıları) bazı veritabanlarımızda, örneğin bazı parametre tablolarında depolarım. '=' Veya 'LIKE' karşılaştırma işleçlerini kullanarak bu tablolardan kayıtları seçtiğim için, bu adları her zaman parantez içinde ya da parantezsiz olarak saklamaya dikkat etmeliyim .

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

veya

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

Ancak MS-SQL, nesne adlarını köşeli ayraçlı veya köşeli ayraçsız kullanabileceğiniz bazı işlevlere sahiptir, örneğin OBJECT_ID () işlevi. Dbfiddle.uk üzerinde minimal bir örnek oluşturdum .

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

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

Şimdi tablonun bu şekilde var olup olmadığını kontrol etmek için OBJECT_ID () kullanabilirsiniz:

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. |

TEST tanımlayıcısını parantez içinde veya parantez olmadan geçirmem önemli değil, ayrıştırıcı parantezleri çıkaracak kadar akıllı.

Eh, bir dizeden parantez kaldıran bir skaler fonksiyon ekleyerek bunu simüle edebilir:

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

Ve sonra bu şekilde kullanın:

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  

Ama sorum şu:

  • T-SQL kullanarak parantez kaldıran herhangi bir gizli yerleşik işlev var mı?

dbfiddle burada

Yanıtlar:


12

T-SQL kullanarak parantez kaldıran herhangi bir gizli yerleşik işlev var mı?

Hayır , T-SQL kullanmıyor.

OBJECT_IDBir olan fonksiyonu. T-SQL'de değil, doğrudan SQL Server yürütülebilir kodunda uygulanır; ve çağrıldığında herhangi bir T-SQL çağırmaz.

Çalışma zamanında, nesne kimliği ifade hizmeti çağrısı yoluyla elde edilir sqlmin!I4ObjIdWstr.

Ardından uygulama, sağlanan dize parametrelerini başvurulan veritabanındaki bir nesnenin kimliğine çözmek için gerekli tüm adımları uygular.

İlk adımlardan biri, dizedeki sınırlandırılmış tanımlayıcılarla ilgilenmeyi içerir sqlmin!CbParseQuotesW. Dar anlamda, bahsettiğiniz kod işlevi budur, ancak doğrudan T-SQL'den erişilemez. Aşağıdaki kodu içerir:

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

... karakterlerin üstesinden gelmek için yapılan testlerdir:

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

Parametreleri bir tanıtıcıya dönüştürme işleminin geri kalanı şunları içerir:

  • Otomatik salt okunur bir işlem başlatma
  • İçerdiği veritabanı gereksinimlerini kontrol etme
  • Name parametresi için olası eşleşmeleri yineleme (doğru harmanlamayı kullanarak)
    • Sağlanan veritabanı adında (veya geçerli bağlam veritabanında)
    • Sağlanan şema adı (veya içinde sys veya kullanıcının varsayılan şema vs.)
  • Gerekli meta veri kilitlerini alma
  • Bir eşleşme için meta veri önbelleğine başvurma
  • Gerekirse meta verileri önbelleğe almak
  • İzinleri kontrol etme (nesne kimliğine erişmek için)
  • İlk eşleşen nesnenin kimliğini döndürme (varsa)

Yan notta, sorudaki kod:

IF OBJECT_ID('TEST') IS NOT NULL

... sadece tabloları aramaz. Bunun için ikinci fonksiyon parametresinin kullanılması gerekir. Buna ek olarak, yalnızca TEST adında şema kapsamındaki herhangi bir nesneyi arar; bu nedenle örneğin BananaSchema.TEST adındaki bir görünüm eşleşir. Daha iyi bir ifade:

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

İlgili Soru-Cevap:


18

Bazen bazı veritabanlarımızda nesne isimlerini saklıyorum

Bu adları her zaman parantez içinde ya da parantezsiz olarak saklamam gerekiyor.

"Nesne adı" teknik olarak tanımlayıcı olarak adlandırılır . Bazı bağlamlarda [ve] veya "ve" ile çevrili bir tanımlayıcı TSQL kodu görünecektir. Bu karakterler tanımlayıcının bir parçası değildir ve asla saklamamalısınız.

Bunun yerine tanımlayıcıyı bir nvarchar (128) (veya sysname) olarak saklayın ve QUOTENAME işlevini kullanarak çalışma zamanında ayırıcıları ekleyin .

QUOTENAME öğesinin tersi, çok parçalı adlarda gezinme ek yeteneğine sahip PARSENAME .

QUOTENAME öğesinin isteğe bağlı ikinci bir parametresi olduğunu ve bu parametre için tek bir tırnak karakteri belirtirseniz QUOTENAME geçerli bir sınırlandırılmış tanımlayıcı ifade oluşturmaz. Varchar değişmez bir ifade yayar.


7

SQL Server besbelli bir şey vardır , iç çıkarır [square brackets](veya diğer tanımlayıcı gibi "double quotes").

Gibi bir tablo oluşturduğunuzda [dbo].[foo], haklısınız, sadece foodepolanır sys.tablesve sys.objectsşemanın [dbo](köşeli parantez ile) bulunmadığından şikayet yoktur .

Ama bu kodun içinde olur CREATE TABLE. PARSENAME()David'in işaret ettiği gibi kullanıyor olabilirler . Hata ayıklayıcıyı bağlamak kesin olarak belirebilir, ama önemli mi?

Ne yaptıklarını görmek için başka bir yere bakabilirsiniz ve sys.sp_renameaslında PARSENAME()kullanılan verim :

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

Ama yine de, neden bazen köşeli parantezleri çıkarmak istediğinizi anladığımdan emin değilim .

Kişisel olarak, kodumun yeterince büyük bir yüzdesi, daha güvenli bir tanımlayıcı kullanıp kullanmadıkları konusunda bilgim veya kontrolüm olmayan ortamlarda kodu kullanacak olan daha geniş bir kitle için yazılmıştır. Bu yüzden her zaman QUOTENAME()her türlü tanımlayıcı içeren komut dosyaları oluşturmak için kullanılan kodu yazarım (ve tercih ederim) .

Onları alıp ihtiyaç duyduklarında bir kez ısırılmaktan ziyade, orada her zaman köşeli parantezleri tercih ederim.


2
@McNets - Bunun yararlı olabileceği küçük vaka sayısı için başka şeylere odaklanmayı tercih ederim. Sen oldukça kolay Baştaki ve sondaki kapalı şerit dize işlevlerini mevcut kullanabilir [ve ]herhangi bir yerine ]]birlikte]
Martin Smith

-6

Köşeli parantez gerektiğinde - bunun nedeni kimliğinizin zaten ayrılmış bir anahtar kelime olmasıdır. Bunları keyfi olarak kullanmak sadece gerekli değildir, aynı zamanda gördüğünüz gibi çok karışıklığa yol açar.

Kanımca, en iyi yol ayrılmış tanımlayıcıları kullanmaktan kaçınmaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.