我才发现,通过纯粹的光彩意外地,那个 SQL Server 允许您创建没有任何名称的变量、参数、表变量、临时表(本地和全局)和临时存储过程(本地和全局)!好吧,至少不是我认为的名字。意思是,您可以指定DECLARE @ INT = 5;
它是有效的 T-SQL:它执行时没有错误,甚至在 SSMS 中都没有用红色波浪下划线标记(本问题末尾显示了带有完整示例列表的代码)。
鉴于数据库标识符的 MSDN 页面指出(强调我的):
有两类标识符:
常规标识符
...定界
标识符
... 常规标识符和定界标识符都必须包含1 到128 个字符。对于本地临时表,标识符最多可以包含 116 个字符。
这当然看起来不像预期的行为,我最初认为这是一个缺陷(不会导致任何错误,但似乎不是“正确”的行为)并提交了一个连接错误:Parameter, Variable, and Temporary表和过程名称/标识符可以为空。
但是,同一个 MSDN 页面还指出:
常规标识符的规则
变量、函数和存储过程的名称必须符合以下 Transact-SQL 标识符规则。
第一个字符必须是以下之一:
- Unicode 标准 3.2 定义的字母。字母的 Unicode 定义包括从 a 到 z、从 A 到 Z 的拉丁字符,以及来自其他语言的字母字符。
下划线 (_)、at 符号 (@) 或井号 (#)。
标识符开头的某些符号在 SQL Server 中具有特殊含义。以 at 符号开头的常规标识符始终表示局部变量或参数,不能用作任何其他类型对象的名称。以数字符号开头的标识符表示临时表或过程。以双数字符号 (##) 开头的标识符表示全局临时对象。尽管数字符号或双数字符号字符可用于开始其他类型的对象的名称,但我们不推荐这种做法。
因此,可以解释为名称的 1 个字符的最低要求(从最上面引用的显示“1 到 128 个字符”的部分)可以通过简单地满足以下任一@
或以下条件#
:
- 它指出那些将是“第一个”字符,而不是某种类型的事物类型的外部指示,并且
- 没有任何内容说明当
@
或#
是第一个字符时,需要2 到128 个字符。
那么,如果这种行为既不是错误也不是缺陷,那么利用这种能力有什么好处吗?是否有合法的用例可以通过执行此操作而受益(即对项目的某些功能性好处,而不仅仅是减少源代码的字符数)?
我想不出一个,除了不专业和在你搬到新雇主时为每个人留下可怕的难以管理的代码之外。
但我也可以看到一个相关的功能问题,因为在许多解析 T-SQL 对象的项目中有许多代码块。如果有人使用 RegEx 模式查找@
后跟诸如 之类的(\w+)
内容,那么它将跳过这些条目。
-- Local variables:
DECLARE @ INT = 99;
DECLARE @@ VARCHAR(10);
SELECT CONVERT(VARCHAR(20), @), STR(@);
SET @@ = STR(@);
SELECT @@;
GO
-- Table Variable:
DECLARE @ TABLE (Col1 INT);
INSERT INTO @ (Col1) VALUES (86);
SELECT * FROM @;
GO
-- Local Temporary Table:
CREATE TABLE # (Col2 DATETIME);
INSERT INTO # (Col2) VALUES (GETDATE());
SELECT * FROM #;
SELECT OBJECT_ID(N'tempdb..#');
GO
-- Global Temporary Stored Procedure
CREATE PROCEDURE ## ( @ INT = 999 )
AS
SELECT @ AS [Huh?];
GO
EXEC ##;
EXEC ## 204;
DECLARE @ INT = 12345;
EXEC ## @ = @;
-- The above also work in another session on the same instance, in a different Database
SELECT * FROM tempdb.sys.parameters tsp WHERE tsp.[object_id] = OBJECT_ID(N'tempdb..##');
-- returns 1 row showing a name of just "@"
PS 我在这里、谷歌和 Microsoft Connect 上搜索过,但找不到任何对“缺失”或“空”变量名或“标识符”的引用。但是,@MartinSmith 确实指出了以下 StackOverflow 答案中使用的这种“能力”以减少代码的字符数:Building an ASCII chart of the most commonly used words in a given text。
似乎这种行为/能力既已知又已弃用。前几天我正在查看sys.dm_os_performance_counters DMV 并注意到以下两个条目:
然后我检查了 MSDN 文档,发现这两个都在 SQL Server 2016页面中已弃用的数据库引擎功能中,在“Transact-SQL”类别下的SQL Server 未来版本部分不支持的功能中:
我能找到的关于此弃用通知的最早参考是在SQL Server 2008 文档中。虽然“已弃用的数据库引擎功能”页面上的版本下拉菜单没有 SQL Server 2005 的条目,但您仍然可以通过https://msdn.microsoft.com/en-us/library访问该文档/ms143729(v=sql.90).aspx,并查看这些项目均未列出。
这些信息使我得出以下结论:
问题第 1 部分(这是错误还是预期行为):
它是有意的,尽管是不受欢迎的行为。
问题第 2 部分(此行为是否有好处):
这里不仅似乎没有任何有益的用例,即使有,也不会因为这种行为/能力被弃用而影响太大,因此不应该继续使用,特别是在新代码中/ 项目。