web-dev-qa-db-ja.com

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

これはすべて機能します:

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

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

53
Brent Ozar

ええと、識別子は常にUnicode/NVARCHARであるため、技術的には、Unicode名を持たないものを作成することはできません????。

ここで発生している問題は、使用されているキャラクターの分類に完全に起因しています。 regular(区切りなし)識別子の規則は次のとおりです。

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

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

また、明確にするために、「文字」と見なされるものと「10進数字」と見なされるものは、各文字がUnicode Character Databaseに割り当てられている properties に基づいています。 Unicodeは、各文字に次のような多くのプロパティを割り当てます。これらのプロパティは、正規表現で「句読点」などと照合するためによく使用されます。たとえば、_\p{Lu}_は(すべての言語/スクリプトで)大文字に一致し、_\p{IsDingbats}_は任意の「絵文字」に一致しますキャラクター。

だから、あなたのやろうとしていること:

_DECLARE @¯\_(ツ)_/¯ INT;
_

___(下線または「下線」)および__(カタカナ文字Tu U + 30C4)文字のみがこれらの規則に適合します。現在、¯\_(ツ)_/¯のすべての文字は区切り識別子には問題ありませんが、残念ながら、変数/パラメータ名とGOTOラベルは区切りできません(ただし、カーソル名は区切り可能です)。

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

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

  • 最初の文字:

    • 分類できるものは何でもかまいませんnicode 3.2の場合 "ID_Start"( "Letters"だけでなく "letterlike numeric characters"も含む)として
    • ___(下線/アンダースコア)または___(全角下線)
    • _@_とすることができますが、変数/パラメータの場合はonly
    • _#_にすることができますが、スキーマバインドオブジェクトの場合は、テーブルとストアドプロシージャのみ(この場合、オブジェクトが一時的であることを示します)
  • 後続の文字:

    • 分類できるものはどれでもnicode 3.2の場合として「ID_Continue」として(「10進数」の数値だけでなく、「間隔と非間隔の結合マーク」、および「句読点の接続」も含まれます)
    • _@_、_#_、または_$_を使用できます
    • 分類された26文字のいずれかを使用できますnicode 3.2の場合形式制御文字として

(事実:「ID_Start」と「ID_Continue」の「ID」は「Identifier」を表します。想像してください;-)

「Unicode Utilities:UnicodeSet」によると:

  • 有効な開始文字

    [:Age = 3.2:]&[:ID_Start = Yes:]

    _-- Test one "Letter" from each of 10+ languages, as of Unicode 3.2
    DECLARE @ᔠᑥᑒᏯשፙᇏᆇᄳᄈლဪඤaൌgೋӁウﺲﶨ   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'.
    */
    _
  • 有効な継続文字

    [:Age = 3.2:]&[:ID_Continue = Yes:]

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

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

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

  1. The Uni-Code:The Search for the True List of Valid Characters for T-SQL Regular Identifiers、Part 1
  2. The Uni-Code:The Search for the True List of Valid Characters for T-SQL Regular Identifiers、Part 2

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

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


「有効な」ASCII文字(_/_や_-_など)が機能しないことに関して:問題は、文字がで定義されているかどうかとは関係ありません。 ASCII文字セット。文字セットを有効にするには、_ID_Start_または_ID_Continue_プロパティのいずれか、または別途記載されている数少ないカスタム文字のいずれかである必要があります。 「正規の」識別子では無効な「有効な」ASCII文字(128文字のうち62文字-ほとんどが句読点と制御文字))がかなりあります。

補足文字について:それらは確かにdelimited識別子で使用できます(そして、ドキュメントは他のことを述べていないように見えます)、それらが通常の識別子で使用できないことが本当であれば、それは最も可能性が高いです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ラベルを区切ることができない理由について:これは、これらのアイテムが言語自体の一部であり、システムテーブルにデータとして入るものではないためと考えられます。

44
Solomon Rutzky

問題の原因となっているのは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 '-'.

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

22
Aaron Bertrand