例如,如果我正在使用 name 创建视图'4aii'
,为什么 SQL Server 会关心它以 a 开头4
?我可以打电话给桌子Fouraii
或IVaii
。
此外,[]
在幕后做了什么来允许将任何字符串用作名称?
一根绳子就是一根绳子,amirite?
例如,如果我正在使用 name 创建视图'4aii'
,为什么 SQL Server 会关心它以 a 开头4
?我可以打电话给桌子Fouraii
或IVaii
。
此外,[]
在幕后做了什么来允许将任何字符串用作名称?
一根绳子就是一根绳子,amirite?
首先,您需要区分数字(数字文字)、字符串(字符串文字)和标识符。
'4aii'
是一个字符串文字,它可以是某个“事物”的值,但它不标识(名称)一个事物。4aii
或[4aii]
将是标识符(如果允许的话)。查询解析器需要理解它正在查看的标记的含义。通过允许名称以数字开头,您通过扩展允许它们仅由数字组成。那么,给定
select 12345 from mytable
,您(和解析器)如何知道12345
是整数文字还是列名?但是,如果您允许标识符仅以字母(或下划线字符)开头,您可以明确地说您是在查看标识符 (
abc123
) 还是字符串文字 ('abc123'
) —— 后者用引号引起来。SQL Server 中的方括号、MySQL 中的反引号 (`) 和 ANSI SQL 兼容引擎中的双引号表示标识符,当您的标识符无法与其他标记区分开时,您可以使用它们:以数字开头,有空格或它们中的其他特殊字符等。因此,
[4aii]
或者"4aii"
清楚地告诉解析器它正在处理一个标识符。一个小 dbfiddle 演示。
是和否:字符串是字符串,但对象/项目名称不是字符串。因此,尽管该陈述是正确的,但它也与您所看到的行为无关。
忽略特定规则的概念推理,“为什么一个工作而不是另一个工作”的技术答案是 SQL Server 遵循(具有最少的定制),Unicode 标准的标识符指南。Unicode 文档可以在这里找到:
Unicode® 标准附件 #31:UNICODE 标识符和模式语法
未包含在其中的标识符
[...]
或者"..."
是“常规”标识符,而包含在其中的标识符是“分隔”标识符。常规标识符是在所有上下文中都有效的名称(即,这些是用这种语言、软件等命名事物的规则)。定界标识符是其他一切:无效且不应工作的名称,但是,如果您将它们包装在其中任何一个定界符中,它们将获得豁免。大多数标识符都可以分隔;它只是GOTO
不能分隔的标签和变量(包括表变量)/参数。区别似乎在于,纯粹为了在 T-SQL 语言中使用而存在的标识符(即不是一个将作为元数据存储在数据文件或日志文件中的名称)不能被分隔(就像你在任何语言)。现在,SQL Server 文档并不完全完整/正确,但它对来自 Unicode 3.2 的有效“标识符”字符(开始和继续)的分类是正确的。如果您想要常规标识符和分隔标识符的实际规则列表,我将它们记录在这里:
完整的 T-SQL 标识符规则列表
要查看证明 Unicode 3.2 分类与 SQL Server 接受的常规标识符之间关系的研究,请访问:
解决对此答案的评论中指出的问题:
_
,#
并且@
在Unicode 规范中进行了说明。第 1.2 节介绍了对基本规则的自定义,甚至提供了四个示例自定义:_
、#
、@
和$
。这 4 个四个“潜在”自定义项与 SQL Server 使用的 4 个完全相同。因此,SQL Server 允许并且@Variable
不#TempTable
指向该 Unicode 文档作为规则的来源。Ident_Start
每个新版本的Ident_Continue
Unicode 标准都添加了字符。查看与这些属性匹配的正确字符集的唯一方法是下载 Unicode 版本 3.2。另外,关于标题中所述的问题,这取决于您对“数字”的定义松散程度。意思是,如果您按照上面直接提到的两篇文章中所示的研究步骤进行操作,这样您就创建了一个表来保存 Unicode Character Database v3.2 和一些其他属性,您可以获得 52 个非- 字母(主要是“数字”)是通过以下查询启动标识符的有效字符:
选择其中一些字符进行测试,我们可以看到它们确实有效:
而且,为了表明它们不仅仅是名称中的“数字”,以下查询证明它们被分配了一个数值(如表中的
NumericValue
列[v3-2].UnicodeCharacterDatabase
所示:但是,它们不是可用于数值运算的数字:
关于解析和需要能够确定
3e2
是数字还是标识符的问题:虽然这是一个考虑因素,并且可能为什么数字被排除在“Ident_start”Unicode 通用类别之外,但它不是通用的,也不一定是为什么SQL Server 将它们排除在外。需要考虑的三点:3e2
它本身是模棱两可的,但如果它至少有一个模式名称,那么它就不会是:dbo.3e2
4aii
一点也不模棱两可。内部解析将能够很容易地将其识别为不是潜在数字MySQL / MariaDB没有这个限制。它们允许使用非分隔标识符,例如
4aii
and3e
,但不允许使用3e2
or300
。我能够在 MySQL 中成功执行以下操作:同样,您不能在 SQL Server 中执行此操作的原因是 SQL Server 遵循 Unicode 标准对标识符的建议。没有具体说明为什么 Unicode 联盟选择了这些字符,但似乎至少是“最佳实践”。尽管如此,正如 MySQL 所证明的那样,可以解析以数字开头的标识符。
您正在观察的是实现的词法分析器规则。这是一个称为词法分析的过程的一部分,这是一种“理解事物”的奇特方式。理想情况下,这将遵守 SQL Spec (
<identifier>
) 中给出的规则。这些规则均由 Microsoft 作为常规标识符规则发布。如果您希望使用不规则标识符,您必须将它们引用或将它们与其他标记(Tsql[]
或双引号""
)“分隔”,这消除了语法歧义的任何可能性。不,以这个为例。
就这么一句话。但是,更重要的是5个字。你知道这是五个词,因为空格很重要。如果你要解析主题、对象和声音,你必须知道它是五个词,才能将其理解为指令。
一个简单的例子,
那是字符串“3e2”吗?数字300?变量名?如果您指的是数字,却忘记了您
3e2 = 500
之前在脚本中写的内容怎么办?规则在那里,以便语法解析器可以理解您的意思。可能有像
4aii
您的问题中提到的那样不含糊的例子 - 但是有一部分标签是模棱两可的。因此,为了避免这种歧义,我们制定了这条规则。在过去的 20 年中,我的视图名为
...但后来我有时间编写一个 osql 脚本以从服务器(SQL Server 2000)中删除该视图(以及其他类似的视图):
除非引用这些名称,否则 DROP VIEW 将不起作用。
和往常一样,对字符串连接以及 EXEC 和 QUOTENAME 的使用有一些神秘的限制。
如果您的工具不允许您创建这样的对象名称……感谢您的小小怜悯。