好吧,标识符始终是Unicode / NVARCHAR
,因此从技术上讲,您不能创建没有Unicode名称anything的任何内容。
您在这里遇到的问题完全归因于所使用字符的分类。常规(即非定界)标识符的规则是:
- 首字母必须为:
- Unicode标准3.2定义的字母。
- 下划线(_),符号(@)或数字符号(#)
- 后续字母可以是:
- Unicode标准3.2中定义的字母。
- 来自基本拉丁语或其他国家文字的小数。
- 下划线(_),符号(@),数字符号(#)或美元符号($)
- 不允许使用空格或特殊字符。
- 不允许使用补充字符。
我加粗了在这种情况下唯一重要的规则。这里的“首字母”规则不相关的原因是,所有局部变量和参数中的首字母始终是“ 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”代表“ Identifier”。想象一下;-)
根据“ Unicode实用程序:UnicodeSet”:
有效的起始字符
[:Age = 3.2:]&[:ID_Start =是:]
-- 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 =是:]
-- 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年3月26日)是没有什么是Unicode的v 3.2。因此,在线搜索无法提供确切的列表。但是,您可以获取Unicode 3.2数据文件,并从此处获取“ ID_Start”和“ ID_Continue”字符列表,以与SQL Server实际使用的内容进行比较。我已经做到了,并确认了与我在“ HOWEVER#1”中所述的规则完全匹配。
以下两篇博客文章详细介绍了查找确切字符列表所采取的步骤,包括导入脚本的链接:
- 统一代码:搜索T-SQL常规标识符的有效字符的真实列表,第1部分
- 统一代码:搜索T-SQL常规标识符的有效字符的真实列表,第2部分
最后,对于只想查看列表而不关心发现和验证它的人,您可以在这里找到:
有效的T-SQL标识符字符的完整列表
(请给页面一点加载时间;这是3.5 MB,几乎47k行)
关于诸如/
和的“有效” ASCII字符无效,-
该问题与是否也在ASCII字符集中定义了这些字符无关。为了有效,该字符必须具有ID_Start
或ID_Continue
属性,或者是单独注明的少数几个自定义字符之一。相当多的“有效” ASCII字符(总共128个中的62个,主要是标点和控制字符)在“常规”标识符中无效。
关于辅助字符:尽管它们肯定可以在定界标识符中使用(并且文档中似乎没有另外说明),但如果确实不能在常规标识符中使用它们,则很可能是由于它们未得到完全支持在SQL Server 2012中引入补充字符感知排序规则之前的内置函数中(它们被视为两个单独的“未知”字符),甚至在100-字符排序规则之前的非二进制排序规则中也无法将它们彼此区分开。级别排序规则(在SQL Server 2008中引入)。
关于ASCII:由于所有标识符均为Unicode NVARCHAR
// UTF-16 LE,因此此处未使用8位编码。该语句SELECT ASCII('ツ');
返回的值63
是“?” (尝试SELECT CHAR(63);
:),因为该字符即使以大写字母“ N”为前缀也肯定不在代码页1252中。但是,该字符在朝鲜语代码页中并且即使没有“ N”,它也会产生正确的结果前缀,在具有韩文默认排序规则的数据库中:
SELECT UNICODE('ツ'); -- 12484
关于影响结果的首字母:这是不可能的,因为局部变量和参数的首字母始终是@
。我们可以控制这些名称的第一个字母实际上是名称的第二个字符。
关于为什么不能区分局部变量名称,参数名称和GOTO
标签的原因:我怀疑这是由于这些项目是语言本身的一部分,而不是某些将其作为数据进入系统表的方式。