Unicodeパラメーターと変数名を作成する方法


53

このすべての機能:

CREATE DATABASE [¯\_(ツ)_/¯];
GO
USE [¯\_(ツ)_/¯];
GO
CREATE SCHEMA [¯\_(ツ)_/¯];
GO
CREATE TABLE [¯\_(ツ)_/¯].[¯\_(ツ)_/¯]([¯\_(ツ)_/¯] NVARCHAR(20));
GO
CREATE UNIQUE CLUSTERED INDEX [¯\_(ツ)_/¯] ON [¯\_(ツ)_/¯].[¯\_(ツ)_/¯]([¯\_(ツ)_/¯]);
GO
INSERT INTO [¯\_(ツ)_/¯].[¯\_(ツ)_/¯]([¯\_(ツ)_/¯]) VALUES (N'[¯\_(ツ)_/¯]');
GO
CREATE VIEW [¯\_(ツ)_/¯].[vw_¯\_(ツ)_/¯] AS SELECT [¯\_(ツ)_/¯] FROM [¯\_(ツ)_/¯].[¯\_(ツ)_/¯];
GO
CREATE PROC [¯\_(ツ)_/¯].[sp_¯\_(ツ)_/¯] @Shrug NVARCHAR(20) AS SELECT [¯\_(ツ)_/¯] FROM [¯\_(ツ)_/¯].[vw_¯\_(ツ)_/¯] WHERE [¯\_(ツ)_/¯] = @Shrug;
GO
EXEC [¯\_(ツ)_/¯].[¯\_(ツ)_/¯].[sp_¯\_(ツ)_/¯] @Shrug = N'[¯\_(ツ)_/¯]';
GO

しかし、あなたはおそらく私がこれでどこに行くのかを見ることができます:@Shrugが欲しくありません、欲しいです@¯\_(ツ)_/¯

これらのいずれも、2008-2017のどのバージョンでも機能しません。

CREATE PROC [¯\_(ツ)_/¯].[sp_¯\_(ツ)_/¯] @[¯\_(ツ)_/¯] NVARCHAR(20) AS SELECT [¯\_(ツ)_/¯] FROM [¯\_(ツ)_/¯].[vw_¯\_(ツ)_/¯] WHERE [¯\_(ツ)_/¯] = @[¯\_(ツ)_/¯];
GO
CREATE PROC [¯\_(ツ)_/¯].[sp_¯\_(ツ)_/¯] [@¯\_(ツ)_/¯] NVARCHAR(20) AS SELECT [¯\_(ツ)_/¯] FROM [¯\_(ツ)_/¯].[vw_¯\_(ツ)_/¯] WHERE [¯\_(ツ)_/¯] = [@¯\_(ツ)_/¯];
GO

だから、ユニコードのストアドプロシージャのパラメータ名を使用する方法はありますか?

回答:


44

さて、識別子は常にUnicode / NVARCHARであるため、技術的にはUnicode名がないものは作成できません🙃。

あなたがここで抱えている問題は、使用されているキャラクターの分類によるものです。通常の(つまり、区切られていない)識別子のルールは次のとおりです。

  • 最初の文字は:
    • Unicode Standard 3.2で定義されている文字。
    • アンダースコア(_)、アットマーク(@)、または番号記号(#)
  • 後続の文字は次のとおりです。
    • Unicode Standard 3.2で定義されている文字。
    • ベーシックラテンまたはその他の国のスクリプトからの10進数
    • アンダースコア(_)、アットマーク(@)、番号記号(#)、またはドル記号($)
  • 埋め込みスペースまたは特殊文字は使用できません。
  • 補助文字は使用できません。

この文脈で重要な唯一のルールを太字にしました。ここで「最初の文字」ルールが関係ないのは、すべてのローカル変数およびパラメーターの最初の文字が常に「アットマーク」であるため@です。

そして、明確にするために、「文字」と見なされるものと「10進数字」と見なされるものは、Unicode文字データベースで各文字が割り当てられるプロパティに基づいています。Unicodeは、is_uppercase、is_lowercase、is_digit、is_decimal、is_combiningなど、多くのプロパティを各文字に割り当てます。これは、人間が文字や10進数字と見なすものではなく、どの文字にこれらのプロパティが割り当てられているかという問題ではありません。これらのプロパティは、「句読点」などに一致するために正規表現でよく使用されます。たとえば、\p{Lu}すべての大文字(すべての言語/スクリプト)に\p{IsDingbats}一致し、「Dingbats」文字に一致します。

だから、あなたの試みで:

DECLARE @¯\_(ツ)_ INT;

のみ_(アンダースコアまたは「低ライン」)および(カタカナ手紙火U + 30C4)文字は、それらの規則に適合します。現在、すべての文字は¯\_(ツ)_/¯デリミタ付き識別子に適していますが、残念ながら変数/パラメータ名とGOTOラベルはデリミタ付きではないようです(ただし、カーソル名は区別できます)。

したがって、変数/パラメータ名については、それらを区切ることができないため、Unicode 3.2の時点で「文字」または「10進数」のいずれかとして修飾される文字のみを使用することに固執しています(まあ、ドキュメントによると、テストする必要があります分類はソートの重みとは異なる方法で処理されるため、ユニコードの新しいバージョンの分類が更新されている場合)。

しかし#1、物事は本来あるべきほど単純ではありません。私は今、研究を完了することができ、記載された定義が完全に正しいわけではないことがわかりました。通常の識別子に有効な文字の正確な(かつ検証可能な)定義は次のとおりです。

  • 最初のキャラクター:

    • Unicode 3.2で「ID_Start」として分類されたもの(「レター」だけでなく「文字のような数字」も含む)
    • することができ_(低ライン/アンダースコア)または_(全角低ライン)
    • にすることができますが@、変数/パラメータのみ
    • にすることができますが#、スキーマバインドオブジェクトの場合は、テーブルとストアドプロシージャのみ(この場合、オブジェクトが一時的であることを示します)
  • 後続の文字:

    • Unicode 3.2で「ID_Continue」(「10進数」の数字だけでなく、「間隔と非間隔の結合マーク」、および「句読点の接続」を含む)として分類されるものであれば何でもかまいません。
    • することができ@#または$
    • Unicode 3.2で形式制御文字として分類されている 26文字のいずれか

(楽しい事実:「ID_Start」と「ID_Continue」の「ID」は「Identifier」の略です。想像してみてください;-)

「Unicode Utilities:UnicodeSet」によると:

  • 有効な開始文字

    [:年齢= 3.2:]&[:ID_Start =はい:]

    -- Test one "Letter" from each of 10+ languages, as of Unicode 3.2
    DECLARE @ᔠᑥᑒᏯשፙᇏᆇᄳᄈლဪඤagೋӁウﺲﶨ   INT;
    -- works
    
    
    -- Test a Supplementary Character that is a "Letter" as of Unicode 3.2
    DECLARE @𝒲 INT;-- Mathematical Script Capital W (U+1D4B2)
    /*
    Msg 102, Level 15, State 1, Line XXXXX
    Incorrect syntax near '0xd835'.
    */
    
  • 有効な継続文字

    [:年齢= 3.2:]&[:ID_Continue =はい:]

    -- Test various decimal numbers, but none are Supplementary Characters
    DECLARE @६৮༦൯௫୫9 INT;
    -- works (including some Hebrew and Arabic, which are right-to-left languages)
    
    
    -- Test a Supplementary Character that is a "decimal" number as of Unicode 3.2
    DECLARE @𝟜 INT; -- MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR (U+1D7DC)
    /*
    Msg 102, Level 15, State 1, Line XXXXX
    Incorrect syntax near '0xd835'.
    */
    -- D835 is the first character in the surrogate pair D835 DFDC that makes up U+1D7DC
    

ただし#2、Unicodeデータベースを検索することすら簡単ではありません。これらの2つの検索は、これらの分類に有効な文字のリストを生成します。これらの文字はUnicode 3.2からのものですが、さまざまな分類の定義はUnicode標準のバージョンによって異なります。つまり、UnicodeのV 10.0で「ID_Start」の定義は(その検索は今日、2018年3月26日を使用しているもの)ではない、それはUnicodeのV 3.2であったもの。そのため、オンライン検索では正確なリストを提供できません。ただし、Unicode 3.2データファイルを取得し、そこから「ID_Start」および「ID_Continue」文字のリストを取得して、SQL Serverが実際に使用しているものと比較できます。そして、私はこれを実行し、上記の「HOWEVER#1」で述べたルールに完全に一致することを確認しました。

次の2つのブログ投稿では、インポートスクリプトへのリンクなど、文字の正確なリストを見つけるための手順を詳しく説明しています。

  1. ユニコード:T-SQL正規識別子の有効な文字の真のリストの検索、パート1
  2. ユニコード:T-SQL正規識別子の有効な文字の真のリストの検索、パート2

最後に、リストを見たいだけで、それを発見して検証するのに何が必要かを気にしない人は、ここでそれを見つけることができます:

有効なT-SQL識別子文字の完全なリスト
(ページをロードする時間を与えてください。3.5MBおよびほぼ47k行です)


「有効」のASCII文字、などについて/-、動作しない:問題は、文字はまた、ASCII文字セットに定義されているかどうかとは関係ありません。有効にするために、キャラクターはID_StartまたはID_Continueプロパティのいずれかを持っているか、別途記載されている数少ないカスタムキャラクターのいずれかでなければなりません。「通常の」識別子では有効ではない「有効な」ASCII文字がかなりあります(合計128個のうち62個—ほとんどが句読点と制御文字)。

補助文字について:区切られた識別子で使用できることは確かですが(そして、ドキュメントはそれ以外の場合は記載されていないように見えます)、通常の識別子で使用できないことが本当なら、それはおそらく完全にサポートされていないためです補足文字認識照合より前の組み込み関数では、SQL Server 2012に導入されました(2つの個別の「不明な」文字として扱われます)。100-より前の非バイナリ照合では、それらを区別することさえできません。レベルの照合(SQL Server 2008で導入)。

ASCIIに関して:すべての識別子はUnicode / NVARCHAR/ UTF-16 LE であるため、8ビットエンコーディングはここでは使用されていません。ステートメントは、「?」SELECT ASCII('ツ');63ある値を返します (試してみてくださいSELECT CHAR(63);)大文字の "N"が前に付いていても、その文字は確かにコードページ1252にはありません。ただし、その文字は韓国語のコードページにあり、 "N 「韓国語のデフォルト照合を使用したデータベースのプレフィックス:

SELECT UNICODE('ツ'); -- 12484

結果に影響する最初の文字に関して:ローカル変数とパラメータの最初の文字は常にであるため、これは不可能@です。これらの名前を制御する最初の文字は、実際には名前の2番目の文字です。

ローカル変数名、パラメーター名、およびGOTOラベルを区切ることができない理由について:これは、これらの項目が言語自体の一部であり、データとしてシステムテーブルに入る方法ではないためと思われます。


本当にありがとう、ありがとう。それが私をこれに導きました。これは素晴らしいブログ投稿になります:gist.github.com/BrentOzar/9b08b5ab2b617847dbe4aa0297b4cd5b
ブレントオザー

8
@BrentOzar最近CTスキャンを受けましたか?
ロスプレッサー

うわー、それは非常に印象的な答えです!そして、ロス・プレッサーの発言を二度目にします。
SQLオタク

22

問題を引き起こしているのはUnicodeではないと思います。ローカル変数またはパラメーター名の場合、その文字は有効なASCII / Unicode 3.2文字ではありません(他のエンティティタイプの場合のように変数/パラメーターのエスケープシーケンスはありません)。

このバッチは正常に機能し、区切りのない識別子の規則に違反しないUnicode文字を使用します。

CREATE OR ALTER PROCEDURE dbo.[💩]
  @ツ int
AS
  CREATE TABLE [#ツ] (ツ int);
  INSERT [#ツ](ツ) SELECT @ツ;
  SELECT +1 FROM [#ツ];
GO
EXEC dbo.[💩] @ツ = 1;

どちらも有効なASCII文字であるスラッシュまたはダッシュを使用しようとすると、すぐに爆撃されます。

Msg 102, Level 15, State 1, Procedure 💩 Incorrect syntax near '-'.

ドキュメントでは、これらの識別子が他のすべての識別子とわずかに異なる規則に従う理由、または他の識別子のようにエスケープできない理由については説明していません。


こんにちはアーロン。ここでいくつかのポイントを明確にするために:1)最初の文字は実際@にはvar / param名のものであるため、最初の文字は問題ではありません。有効な文字が前に付いていても、機能していない文字はどの位置でも機能しません。2)ドキュメントには、補助文字は通常の識別子では使用できないと記載されていますが(これは私が試したすべてのケースに当てはまるようです)、埋め込みスペースのように区切り識別子に制限はありません。また、これらはDB内のものではなくT-SQL言語の一部であるため、これらは異なると思います。
ソロモンラッツキー

@SolomonRutzky問題は、他のエンティティのようにパラメーター名を区切ることができないという単純かつ完全な問題だと思います。パラメータ名を角かっこまたは二重引用符で囲むことができる場合、これらの文字を任意の位置に配置できます。この質問では、パラメーター名にUnicode文字を使用できないと仮定していますが、明らかにそうではありません。使用できる Unicode文字と、使用できない ASCII文字があります。
アーロンバートランド

はい、変数/パラメータの名前とGOTOラベルを区切ることができる場合、唯一の制限は長さになることに同意します。これらの少数のアイテムの解析および/または処理が異なるレベルで発生するか、または区切り値を実行できないようにする他の制約があるとのみ想定できます。少なくとも、それがor意的でも見落としでもないことを願っています。
ソロモンラツキー

(私が少し前に答えたときあなたのコメントへの更新を見なかった)。はい、質問はOPがUnicode文字を使用できないことを意味しますが、すべての名前が常にUnicode / NVARCHARであるため、質問の言い回しは技術的に間違っています。ここでは使用されていない8ビットのエンコードなので、これはASCIIとは関係ありません。さまざまな8ビットコードページに一部の文字が存在する場合でも、ここのすべての文字はUnicode文字です。私の答えで説明したように、どの文字を使用できるかは、どの文字がis_alphabeticまたはでタグ付けされたかという問題ですnumeric_type=decimal
ソロモンラッツキー

私は、うんちでいっぱいのストアドプロシージャを見たことがありますが、名前を付けたことはありません!
ミッチ小麦
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.