如何创建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

因此,有没有办法使用Unicode存储过程参数名称?

Answers:


44

好吧,标识符始终是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 @ᔠᑥᑒᏯשፙᇏᆇᄳᄈლဪඤ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'.
    */
  • 有效的延续字符

    [: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”中所述的规则完全匹配。

以下两篇博客文章详细介绍了查找确切字符列表所采取的步骤,包括导入脚本的链接:

  1. 统一代码:搜索T-SQL常规标识符的有效字符的真实列表,第1部分
  2. 统一代码:搜索T-SQL常规标识符的有效字符的真实列表,第2部分

最后,对于只想查看列表而不关心发现和验证它的人,您可以在这里找到:

有效的T-SQL标识符字符的完整列表
(请给页面一点加载时间;这是3.5 MB,几乎47k行)


关于诸如/和的“有效” ASCII字符无效,-该问题与是否也在ASCII字符集中定义了这些字符无关。为了有效,该字符必须具有ID_StartID_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标签的原因:我怀疑这是由于这些项目是语言本身的一部分,而不是某些将其作为数据进入系统表的方式。


太棒了,谢谢。这使我想到
Brent Ozar

8
@BrentOzar您最近进行过CT扫描吗?
罗斯·普斯德

哇,这真是一个了不起的答案!我赞同罗斯·普纳德的话。
SQL Nerd

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)文档仅声明补充字符不能在常规标识符中使用(我尝试过的所有情况似乎都是这种情况),但是对分隔标识符没有任何限制,就像嵌入空格一样。另外,我相信它们是不同的,因为它们是T-SQL语言的一部分,而不是数据库中的东西。
所罗门·鲁兹基'18

@SolomonRutzky我觉得问题很简单,那就是参数名称不能像其他实体一样被定界。如果我可以将方括号或双引号括在参数名称周围,则可以将这些字符中的任何一个放在任何位置。该问题假定您不能在参数名称中使用Unicode字符,显然不是这种情况。有一些Unicode字符,你可以使用,而且你一些ASCII字符不能
亚伦·伯特兰

是的,我同意,如果GOTO允许对变量/参数名称和标签进行定界,那么唯一的限制就是长度。我只能假设解析和/或处理这几项的操作发生在不同的级别,或者具有其他一些限制,使得使用分隔值不可行。至少我希望这不是武断或疏忽大意。
所罗门·鲁茨基

(我刚才回答时没有看到您评论的更新)。是的,这个问题确实暗示OP无法使用Unicode字符,但是该问题的措词在技术上是不正确的,因为所有名称始终都是Unicode / NVARCHAR。这与ASCII没有关系,因为这是8位编码,在此未使用。即使所有的8位代码页中也存在某些字符,此处的所有字符均为Unicode字符。正如我在回答中所解释的那样,可以使用哪个字符是使用is_alphabetic或标记哪个字符的问题numeric_type=decimal
所罗门·鲁茨基

我看过存储过程中充满了便便但从未命名!
米奇·
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.