オブジェクト名の引用符を外すためのMS-SQLの(非表示の)組み込み関数はありますか?


12

オブジェクト名(識別子)を一部のデータベース、たとえば一部のパラメーターテーブルに保存することがあります。'='または 'LIKE'比較演算子を使用してこれらのテーブルからレコードを選択するため、これらの名前を常に角かっこ付きまたは角括弧なしで保存するように注意する必要があります

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

または

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

ただし、MS-SQLには、OBJECT_ID()関数など、角括弧の有無にかかわらずオブジェクト名を使用できるいくつかの関数があります。私は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

これで、OBJECT_ID()を使用して、テーブルTESTが次のように存在するかどうかを確認できます。

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をブラケットの有無に関係なく渡してもかまいません。パーサーはブラケットを削除するのに十分スマートです。

まあ、1つの文字列から角かっこを削除するスカラー関数を追加することで、これをシミュレートできます。

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

そして、それを次のように使用します。

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  

しかし、私の質問は:

  • T-SQLを使用して角かっこを削除する非表示の組み込み関数はありますか?

ここ dbfiddle

回答:


12

T-SQLを使用して角かっこを削除する非表示の組み込み関数はありますか?

いいえ、T-SQLは使用しません

OBJECT_IDある固有の関数が。T-SQLではなく、SQL Server実行可能コードに直接実装されます。呼び出されてもT-SQLは呼び出されません。

実行時に、を呼び出す式サービスを介してオブジェクトIDが取得されますsqlmin!I4ObjIdWstr

次に、実装は、提供された文字列パラメーターを解決して、参照されるデータベース内のオブジェクトのIDにするために必要なすべての手順を実行します。

最初のステップの1つには、文字列内の区切られた識別子をを介して処理することが含まれますsqlmin!CbParseQuotesW。狭義では、それはあなたが参照しているコード関数ですが、T-SQLから直接アクセスすることはできません。次のコードが含まれています。

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

...これは、文字を処理するためのテストです。

  • 16進数22 = 12月34 = "
  • 16進数2E = 12月46 = .
  • 16進数5B = 12月91 = [
  • 16進数5D = 12月93 = ]

パラメーターをIDに解決する残りのプロセスには、以下が含まれます。

  • 自動読み取り専用トランザクションの開始
  • 含まれるデータベース要件の確認
  • 名前パラメーターの可能な一致を反復処理する(正しい照合を使用)
    • 指定されたデータベース名(または現在のコンテキストデータベース)
    • 指定されたスキーマ名(またはsys、またはユーザーのデフォルトのスキーマなど)
  • 必要なメタデータロックを取得する
  • 一致するメタデータキャッシュを調べる
  • 必要に応じてメタデータをキャッシュにフェッチする
  • 権限の確認(オブジェクトIDにアクセスするため)
  • 最初に一致したオブジェクトのID(ある場合)を返します

余談ですが、質問のコード:

IF OBJECT_ID('TEST') IS NOT NULL

...テーブルのみを検索しません。そのためには、2番目の関数パラメーターを使用する必要があります。また、それだけで探し任意のスキーマスコープオブジェクトの名前TEST - BananaSchema.TESTという名前のビューには、例えば、マッチするようにします。より良い表現は:

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

関連するQ&A:


18

時々私はいくつかのデータベースにオブジェクト名を保存します

この名前は常に角かっこ付きまたは角括弧なしで保存するように注意する必要があります。

「オブジェクト名」は技術的に識別子と呼ばます。一部のコンテキストでは、識別子は[および]または "および"で囲まれたTSQLコードとして表示されます。これらの文字は識別子の一部ではないため、保存しないでください。

代わりに、識別子をnvarchar(128)(またはsysname)として保存し、QUOTENAME関数を使用して実行時に区切り文字を追加します。

QUOTENAMEの逆はPARSENAMEで、マルチパート名をナビゲートする追加機能があります。

QUOTENAMEにはオプションの2番目のパラメーターがあり、そのパラメーターに単一引用符を指定した場合、QUOTENAMEは有効な区切りID式を作成しないことに注意してください。varcharリテラル式を発行します。


7

SQL Serverには、明らかに内部を削除するもの[square brackets](またはのような他の識別子"double quotes")があります。

あなたのようなテーブルを作成するときに[dbo].[foo]、あなたしている右、のみfooに保存されますsys.tablessys.objects、そして何のスキーマという文句はありません[dbo](角括弧付き)が見つかりませんでしたが。

しかし、これはのコード内で発生しますCREATE TABLEPARSENAME()Davidが指摘したように、彼らはを使用している可能性があります。デバッガを接続することは確かに示すことができますが、それは重要ですか?

あなたは彼らが何をしているのかを見るために他の場所を見ることができます、そしてsys.sp_rename実際にはそれPARSENAME()が使われることをもたらします:

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

しかし、繰り返しますが、なぜ角かっこをときどき削除したいのかわかりません。

私個人的には、私のコードの十分に大きな割合が幅広いユーザー向けに書かれており、私は彼らが安全でない識別子を使用しているかどうかについて私が知識も制御もしていない環境でコードを使用します。そのため、私は常にQUOTENAME()、あらゆる種類の識別子を含むスクリプトを生成するために使用するコードを持っています(そして好むでしょう)。

角かっこはいつでもそこに持っていき、必要なときに一度かむのではなく、ずっとそこに置いておきたいです。


2
@McNets-これが役立つ可能性のある非常に少数のケースでは、他のことに焦点を当てたほうがいいと思います。あなたは非常に簡単に、先頭と末尾取り除くために、既存の文字列関数を使用することができます [し、]そしていずれかを交換する]]]
マーティン・スミス

-6

角括弧が必要な場合 -これは、識別子がすでに予約済みキーワードであるためです。それらを任意に使用することは必要ではないだけでなく、ご覧のように混乱を招きます。

私の意見では、最善の方法は、そもそも予約済み識別子を使用しないことです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.