Sql-Server

如何創建 Unicode 參數和變數名

  • April 13, 2018

所有這些都有效:

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 儲存過程參數名稱呢?

好吧,標識符總是 Unicode / NVARCHAR,所以從技術上講,你不能創建任何沒有 Unicode 名稱的東西🙃。

您在這裡遇到的問題完全是由於所使用的字元的分類。正常(即非分隔)標識符的規則是:

  • 第一個字母必須是:

    • Unicode 標準 3.2 定義的字母。
    • 下劃線 (_)、at 符號 (@) 或數字元號 (#)
  • 後續字母可以是:

    • Unicode 標準 3.2 中定義的字母。
    • 來自基本拉丁文或其他國家文字的十進制數字。
    • 下劃線 (_)、at 符號 (@)、數字元號 (#) 或美元符號 ($)
  • 不允許嵌入空格或特殊字元。

  • 不允許使用補充字元。

我加粗了在這種情況下唯一重要的規則。“首字母”規則在這裡不相關的原因是所有局部變數和參數中的首字母始終是“at 符號” @

並且要明確:什麼被認為是“字母”和什麼被認為是“十進制數字”是基於每個字元在 Unicode 字元數據庫中分配的屬性。Unicode 為每個字元分配了許多屬性,例如:is_uppercase、is_lowercase、is_digit、is_decimal、is_combining 等。這不是我們凡人認為字母或十進制數字的問題,而是哪些字元被分配了這些屬性。這些屬性通常在正則表達式中用於匹配“標點符號”等。例如,\p{Lu}匹配任何大寫字母(跨所有語言/腳本),並\p{IsDingbats}匹配任何“Dingbats”字元。

因此,在您嘗試執行以下操作時:

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

只有_(下劃線或“低線”)和(片假名字母 Tu U+30C4)字元符合這些規則。現在,其中的所有字元¯\_(ツ)_/¯都可以用於分隔標識符,但不幸的是,變數/參數名稱和標籤似乎GOTO無法分隔(儘管游標名稱可以)。

因此,對於變數/參數名稱,由於它們無法分隔,因此您只能使用符合 Unicode 3.2 的“字母”或“十進制數字”的字元(好吧,根據文件;我需要測試如果分類已針對較新版本的 Unicode 進行了更新,因為分類的處理方式與排序權重不同)。

但是#1,事情並不像他們應該的那樣直截了當。我現在已經能夠完成我的研究,並且發現所述定義並不完全正確。哪些字元對正常標識符有效的精確(和可驗證)定義是:

  • 第一個字元:

    • 可以是Unicode 3.2中歸類為“ID_Start”的任何內容(包括“字母”但也包括“類似字母的數字字元”)
    • 可以是_(低線/下劃線)或_(全形低線)
    • 可以@,但僅限於變數/參數
    • 可以#,但如果是模式綁定對象,則僅適用於表和儲存過程(在這種情況下,它們表明該對像是臨時的)
  • 後續字元:

    • 可以是Unicode 3.2中分類為“ID_Continue”的任何內容(包括“十進制”數字,還包括“間距和非間距組合標記”以及“連接標點符號”)
    • 可以是@, #, 或$
    • 可以是Unicode 3.2中分類為格式控製字元的 26 個字元中的任何一個

(有趣的事實:“ID_Start”和“ID_Continue”中的“ID”代表“標識符”。想像一下;-)

根據“Unicode 實用程序: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

但是#2,即使搜尋 Unicode 數據庫也不是那麼容易。這兩個搜尋確實為這些分類生成了一個有效字元列表,並且這些字元來自 Unicode 3.2,但是各種分類的定義隨著 Unicode 標準的版本而變化。這意味著,Unicode v 10.0 中“ID_Start”的定義(該搜尋今天使用的內容,2018-03-26)Unicode v 3.2 中的定義不同。因此,線上搜尋無法提供準確的列表。但是您可以獲取 Unicode 3.2 數據文件並從那裡獲取“ID_Start”和“ID_Continue”字元列表,以與 SQL Server 實際使用的字元進行比較。我已經做到了這一點,並確認與我在上面“HOWEVER #1”中所述的規則完全匹配。

以下兩篇博文詳細介紹了查找確切字元列表所採取的步驟,包括導入腳本的連結:

  1. Uni-Code:搜尋 T-SQL 正則標識符的有效字元的真實列表,第 1 部分
  2. Uni-Code:搜尋 T-SQL 正則標識符的有效字元的真實列表,第 2 部分

最後,對於只想查看列表而不關心發現和驗證它需要什麼的人,您可以在此處找到:

完整的有效 T-SQL 標識符字元列表

(請給頁面一點時間來載入;它是 3.5 MB 和近 47k 行)


關於“有效” ASCII 字元,例如/and -,不起作用:該問題與字元是否也在 ASCII 字元集中定義無關。為了有效,該字元必須具有ID_StartorID_Continue屬性,或者是為數不多的單獨註明的自定義字元之一。有相當多的“有效” ASCII 字元(總共 128 個中的 62 個 - 主要是標點符號和控製字元)在“正常”標識符中無效。

關於補充字元:雖然它們當然可以用於分隔標識符(並且文件似乎沒有另外說明),但如果確實不能在正常標識符中使用它們,那很可能是由於它們沒有得到完全支持在 SQL Server 2012 中引入 Supplementary Character-Aware Collat​​ions 之前的內置函式中(它們被視為兩個單獨的“未知”字元),在 100-級別排序規則(在 SQL Server 2008 中引入)。

關於 ASCII:這裡沒有使用 8 位編碼,因為所有標識符都是 Unicode NVARCHAR// UTF-16 LE。該語句SELECT ASCII('ツ');返回一個值為63“?”的值。(嘗試SELECT CHAR(63);:)因為該字元,即使以大寫字母“N”為前綴,也肯定不在程式碼頁 1252 中。但是,該字元在韓語程式碼頁中,並且即使沒有“N”,它也會產生正確的結果" 前綴,在具有韓語預設排序規則的數據庫中:

SELECT UNICODE('ツ'); -- 12484

關於影響結果的第一個字母:這是不可能的,因為局部變數和參數的第一個字母始終是@. 我們為這些名稱控制的第一個字母實際上是名稱的第二個字元。

GOTO關於為什麼不能分隔局部變數名稱、參數名稱和標籤:我懷疑這是因為這些項目是語言本身的一部分,而不是作為數據進入系統表的東西。

引用自:https://dba.stackexchange.com/questions/201598