it-swarm.com.de

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

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, speichern diese Namen immer mit oder ohne Klammern.

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 für 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

12
McNets

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

Nein , ohne T-SQL.

OBJECT_ID ist 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 Ausdrucksdienst abgerufen, der sqlmin!I4ObjIdWstr aufruft.

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 beliebigen 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. Außerdem wird nur nach any Objekt mit Schemabereich mit dem Namen TEST gesucht, sodass beispielsweise eine Ansicht mit dem Namen BananaSchema.TEST übereinstimmt. Ein besserer Ausdruck wäre:

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

Verwandte Fragen und Antworten:

12
Paul White 9

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 Trennzeichen zur Laufzeit mit der Funktion QUOTENAME hinzu.

Die Umkehrung von QUOTENAME ist PARSENAME , was die zusätzliche Fähigkeit bietet, durch mehrteilige Namen zu navigieren.

Beachten Sie, dass QUOTENAME über einen optionalen zweiten Parameter verfügt. Wenn Sie für diesen Parameter ein einfaches Anführungszeichen angeben, erstellt QUOTENAME keinen gültigen, durch Trennzeichen getrennten Bezeichnerausdruck. Es gibt einen varchar-Literalausdruck aus.

SQL Server hat offensichtlich etwas intern, das [square brackets] (Oder andere Bezeichner wie "double quotes") Entfernt.

Wenn Sie eine Tabelle wie [dbo].[foo] Erstellen, haben Sie Recht, nur foo wird in sys.tables Und sys.objects Gespeichert, und es gibt keine Beschwerde, dass das Schema [dbo] (Mit den eckigen Klammern) wurde nicht gefunden.

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

Sie können woanders nachsehen, was sie tun, und sys.sp_rename Ergibt tatsächlich, dass PARSENAME() 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 ich nur manchmal die eckigen Klammern entfernen möchte.

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), der QUOTENAME() verwendet, um Skripte zu generieren, die jede Art von Kennung enthalten.

Ich hätte die eckigen Klammern viel lieber die ganze Zeit dort, als sie wegzunehmen und das eine Mal gebissen zu werden, wenn sie gebraucht wurden.

7
Aaron Bertrand