如何检查建议的 T-SQL 对象名称是否有效或是否需要用方括号括起来

How to check if a proposed T-SQL object name is valid or needs to be enclosed in square brackets

可以向我的存储过程传递任意字符串 @String 作为 varcharnvarchar,长度不超过 128 个字符。

存储过程需要使用该 @String 值作为对象名称,即 table、字段、视图或类似名称。

我如何确定所提供的 @String 的值本身是否是一个有效的对象名称 - 即不是保留字并且不包含无效字符 - 或者它是否需要包含在(和转义任何包含的)方括号,以便使成为有效的对象名称。

例如,"X"、"Foo" 和 "C:\Temp\X.csv" 是有效的对象名称(是的,我已经成功地按原样使用了 "C:\Temp\X.csv")并且可以使用未修改,而 "Select"、"AB]C" 和“1_ABC”无效,需要更改为“[Select]”、“[AB]]C] ”和“[1_ABC]”

我更喜欢不会的解决方案只是尝试创建一个具有该名称的对象,然后检查它是否有效。

将优先考虑适用于更广泛 SQL 服务器版本的答案,而不仅仅是最新版本,较短、不太复杂的代码将优先于更长、更复杂的代码。

作为导致我问这个问题的问题的一个例子,我的 SP 可以传递一个 @Name,它可能是 "C:\Temp\X.csv" 或 "ABC" 或 "SELECT" 管他呢。我的 SP 然后创建一个 table,填充它并 然后 (所以我不必使用动态 SQL)使用 [= 将它的名称更改为 @Name 17=]。我需要 QUOTENAME(@Name) where @Name = "SELECT",但在其他两种情况下不需要,产生(在 SSMS 对象资源管理器中)tables "dbo.C:\Temp\X.csv"、"dbo.ABC" 和 "dbo.SELECT"。但是,在 运行 SP 的其余部分之前,我还需要检查这些对象是否存在,如果我 QUOTENAME "C:\Temp\X.csv",则在将其作为新名称传递给 [=17] 之前=],它在SSMS对象资源管理器中显示为"dbo.[C:\Temp\X.csv]",我必须使用IF OBJECT_ID('[[C:\Temp\X.csv]]]') IS NOT NULL才能成功确定它存在,不是IF OBJECT_ID('[C:\Temp\X.csv]') IS NOT NULL

使用 sp_rename 时,对象的新名称永远不需要转义,因此只需使用传入的 @Name 值即可。

确实 OBJECT_ID 有时可能需要转义名称,但由于有更直接的测试可用,同样不需要转义,我建议您改用它作为测试:

IF EXISTS(SELECT * from sys.tables where name = @Name)
...

(或者您可以查询 sys.objects,由您决定)

我最初设想您使用的是动态 SQL 中的名称。在动态 SQL 上下文中,我建议总是使用 QUOTENAME 转义名称,而不是尝试确定它是否需要转义。

此代码可能有助于了解何时使用 QUOTENAME。它未在 sp_rename.

中使用
CREATE PROCEDURE TestObjectNames
    @Name SYSNAME
AS

DECLARE @SQL NVARCHAR(MAX);

-- Create temporary table
CREATE TABLE Temp (ID INT, Name SYSNAME);
-- Load temporary table
INSERT INTO Temp SELECT database_id, name FROM sys.databases;
-- Check existance of table
IF NOT EXISTS(SELECT * FROM sys.tables WHERE name = @Name)
    -- Rename table (Don't use QUOTENAME)
    EXEC sp_rename 'Temp', @Name;;
-- Fetch object id of new table (Use QUOTENAME)
SELECT OBJECT_ID(QUOTENAME(@Name)) AS NewTableID;
-- Select from table dynamically (Use QUOTENAME)
SET @SQL = 'SELECT COUNT(*) AS NewTableCount FROM ' + QUOTENAME(@Name);
EXEC sp_executesql @SQL;
-- Drop new table dynamically (Use QUOTENAME)
SET @SQL = 'DROP TABLE ' + QUOTENAME(@Name);
EXEC sp_executesql @SQL;
GO

EXEC TestObjectNames 'SELECT';
EXEC TestObjectNames 'C:\Temp\X.csv';
EXEC TestObjectNames 'AB]C';
EXEC TestObjectNames '1_ABC';
EXEC TestObjectNames 'ABC';