Gibt es in MS-SQL eine (versteckte) integrierte Funktion zum Aufheben der Angabe von Objektnamen?

12

Manchmal speichere ich Objektnamen (Bezeichner) in einigen unserer Datenbanken, zum Beispiel in einigen Parametertabellen. Da ich Datensätze aus diesen Tabellen mit den Vergleichsoperatoren '=' oder 'LIKE' auswähle, muss ich darauf achten, diese Namen immer mit oder ohne Klammern zu speichern .

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

oder

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

MS-SQL verfügt jedoch über einige Funktionen, in denen Sie Objektnamen mit oder ohne Klammern verwenden können, z. B. die Funktion OBJECT_ID (). Ich habe ein minimales Beispiel auf dbfiddle.uk eingerichtet .

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

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

Jetzt kann ich mit OBJECT_ID () überprüfen, ob die Tabelle TEST auf folgende Weise vorhanden ist:

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

Es spielt keine Rolle, ob ich den Bezeichner-TEST mit oder ohne Klammern übergebe. Der Parser ist intelligent genug, um die Klammern zu entfernen.

Nun, ich kann dies simulieren, indem ich eine Skalarfunktion hinzufüge, die Klammern aus einer Zeichenfolge entfernt:

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

Und dann benutze es so:

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  

Aber meine Frage ist:

  • Gibt es eine versteckte integrierte Funktion, mit der Klammern mithilfe von T-SQL entfernt werden?

dbfiddle hier

McNets
quelle

Antworten:

12

Gibt es eine versteckte integrierte Funktion, mit der Klammern mithilfe von T-SQL entfernt werden?

Nein , T-SQL wird nicht verwendet.

OBJECT_IDist eine intrinsische Funktion. Es wird direkt im ausführbaren SQL Server-Code implementiert, nicht in T-SQL. und es ruft beim Aufrufen kein T-SQL auf.

Zur Laufzeit wird die Objekt-ID über den Ausdrucksdienstaufruf abgerufen sqlmin!I4ObjIdWstr.

Die Implementierung durchläuft dann alle erforderlichen Schritte, um die bereitgestellten Zeichenfolgenparameter in die ID eines Objekts in der referenzierten Datenbank aufzulösen.

Einer der ersten Schritte umfasst den Umgang mit durch Trennzeichen getrennten Bezeichnern in der Zeichenfolge über sqlmin!CbParseQuotesW. Im engeren Sinne ist dies die Codefunktion, auf die Sie sich beziehen, auf die jedoch nicht direkt über T-SQL zugegriffen werden kann. Es enthält den folgenden Code:

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

... welche Tests sind, um mit den Zeichen umzugehen:

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

Der Rest des Prozesses zum Auflösen der Parameter in eine ID umfasst:

  • Starten einer automatischen schreibgeschützten Transaktion
  • Überprüfen der enthaltenen Datenbankanforderungen
  • Durchlaufen möglicher Übereinstimmungen für den Namensparameter (unter Verwendung der richtigen Sortierung)
    • Im angegebenen Datenbanknamen (oder der aktuellen Kontextdatenbank)
    • Im angegebenen Schemanamen (oder sys oder im Standardschema des Benutzers usw.)
  • Nehmen Sie die erforderlichen Metadatensperren
  • Konsultieren Sie den Metadaten-Cache für eine Übereinstimmung
  • Bei Bedarf Metadaten in den Cache holen
  • Überprüfen von Berechtigungen (um auf die Objekt-ID zuzugreifen)
  • Rückgabe der ID des ersten übereinstimmenden Objekts (falls vorhanden)

Nebenbei bemerkt, der Code in der Frage:

IF OBJECT_ID('TEST') IS NOT NULL

... sucht nicht nur nach Tabellen. Dazu müsste der zweite Funktionsparameter verwendet werden. Darüber hinaus sieht es nur für jeden schema-scoped Objekt mit dem Namen TEST - so eine Ansicht namens BananaSchema.TEST würde passen, zum Beispiel. Ein besserer Ausdruck wäre:

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

Verwandte Fragen und Antworten:

Paul White 9
quelle
18

Manchmal speichere ich Objektnamen in einigen unserer Datenbanken

Ich muss darauf achten, diese Namen immer mit oder ohne Klammern zu speichern.

Ein "Objektname" wird technisch als Bezeichner bezeichnet . In einigen Kontexten wird ein Bezeichner als TSQL-Code angezeigt, der von [und] oder "und" umgeben ist. Diese Zeichen sind nicht Teil des Bezeichners, und Sie sollten sie niemals speichern.

Speichern Sie den Bezeichner stattdessen als nvarchar (128) (oder sysname) und fügen Sie die Begrenzer zur Laufzeit mit der Funktion QUOTENAME hinzu .

Die Umkehrung von QUOTENAME ist PARSENAME , mit dem zusätzlich mehrteilige Namen navigiert werden können.

Beachten Sie, dass QUOTENAME einen optionalen zweiten Parameter hat. Wenn Sie für diesen Parameter ein einfaches Anführungszeichen angeben, erstellt QUOTENAME keinen gültigen Ausdruck mit getrenntem Bezeichner. Es gibt einen varchar-wörtlichen Ausdruck aus.

David Browne - Microsoft
quelle
7

SQL Server hat offensichtlich etwas Internes , das entfernt wird [square brackets](oder andere Bezeichner wie "double quotes").

Wenn Sie eine Tabelle wie erstellen [dbo].[foo], haben Sie Recht, werden nur fooin sys.tablesund gespeichert sys.objects, und es gibt keine Beschwerde darüber, dass das Schema [dbo](mit den eckigen Klammern) nicht gefunden wurde.

Dies geschieht jedoch im Code für CREATE TABLE. Sie können verwenden PARSENAME(), wie David betonte. Das Anschließen des Debuggers könnte sicher anzeigen, aber spielt es eine Rolle?

Sie können woanders suchen, um zu sehen, was sie tun, und sys.sp_renametatsächlich ergibt sich das, PARSENAME()was verwendet wird:

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

Aber auch hier bin ich mir nicht sicher, warum Sie die eckigen Klammern nur manchmal entfernen möchten .

Für mich persönlich ist ein ausreichend großer Prozentsatz meines Codes für ein breiteres Publikum geschrieben, das den Code in Umgebungen verwendet, in denen ich keine Kenntnis oder Kontrolle darüber habe, ob sie unsichere Kennungen verwenden. Ich habe und werde also immer Code schreiben (und bevorzugen), mit QUOTENAME()dem Skripte generiert werden, die jede Art von Kennung enthalten.

Ich würde die eckigen Klammern viel lieber die ganze Zeit dort haben, als sie wegzunehmen und das eine Mal gebissen zu werden, wenn sie gebraucht werden.

Aaron Bertrand
quelle
2
@McNets - Für die winzige Anzahl von Fällen, in denen dies nützlich sein könnte, würde ich mich lieber auf andere Dinge konzentrieren. Sie können ganz einfach vorhandene Zeichenfolgenfunktionen verwenden, um führende und nachfolgende zu entfernen [und ]alle ]]durch]
Martin Smith
-6

Wenn eckige Klammern benötigt werden , liegt dies daran, dass Ihre Kennung bereits ein reserviertes Schlüsselwort ist. Eine willkürliche Verwendung ist nicht nur nicht erforderlich, sondern führt auch zu großer Verwirrung, wie Sie sehen können.

Meiner Meinung nach ist es am besten, reservierte Bezeichner überhaupt nicht zu verwenden.

Jinzai
quelle