AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 195923
Accepted
McNets
McNets
Asked: 2018-01-23 06:14:48 +0800 CST2018-01-23 06:14:48 +0800 CST 2018-01-23 06:14:48 +0800 CST

MS-SQL 上是否有任何(隐藏的)内置函数来取消引用对象名称?

  • 772

有时我将对象名称(标识符)存储在我们的某些数据库中,例如某些参数表中。因为我使用 '=' 或 'LIKE' 比较运算符从这些表中选择记录,所以我必须注意始终使用或不使用括号来存储这些名称。

IF EXISTS (SELECT 1 FROM MYTABLE WHERE OBJ_NAME = '[TABLE_NAME]';

或者

IF EXISTS (SELECT 1 FROM MYTABLE WHERE OBJ_NAME = 'TABLE_NAME';

但是,MS-SQL 有一些函数,您可以在其中使用带或不带括号的对象名称,例如 OBJECT_ID() 函数。我在dbfiddle.uk上设置了一个最小示例。

CREATE TABLE TEST
(
    ID     INT IDENTITY(1,1) PRIMARY KEY,
    OBJECT sysname NOT NULL
);
GO

INSERT INTO TEST VALUES ('[obj1]'),('obj2'),('obj3'),('[obj4]');
GO

现在我可以使用 OBJECT_ID() 来检查表 TEST 是否以这种方式存在:

IF OBJECT_ID('TEST') IS NOT NULL
BEGIN
    SELECT 'TEST EXISTS.' OBJECT_ID;
END
GO

| OBJECT_ID    |
| :----------- |
| TEST EXISTS. |

IF OBJECT_ID('[TEST]') IS NOT NULL
BEGIN
    SELECT '[TEST] EXISTS.' OBJECT_ID;
END
GO

| OBJECT_ID      |
| :------------- |
| [TEST] EXISTS. |

我是否通过带有或不带有括号的标识符 TEST 都没有关系,解析器足够聪明,可以删除括号。

好吧,我可以通过添加一个从一个字符串中删除括号的标量函数来模拟这一点:

CREATE FUNCTION UNQUOTENAME(@TXT NVARCHAR(MAX)) 
RETURNS NVARCHAR(MAX)
AS
    BEGIN
        RETURN IIF(LEFT(@TXT, 1) = N'[' AND RIGHT(@TXT, 1) = N']', 
                   SUBSTRING(@TXT, 2, LEN(@TXT) -  2), 
                   @TXT);
    END;
GO

然后以这种方式使用它:

SELECT dbo.UNQUOTENAME (N'[FIELD]') NAME1, N'FIELD' NAME2;
GO

NAME1 | NAME2
:---- | :----
FIELD | FIELD

SELECT ID, OBJECT 
FROM   TEST 
WHERE OBJECT LIKE 'obj%';
GO

ID | OBJECT
-: | :-----
 2 | obj2  
 3 | obj3  

SELECT ID, dbo.UNQUOTENAME(OBJECT) 
FROM   TEST 
WHERE  dbo.UNQUOTENAME(OBJECT) LIKE 'obj%';
GO

ID | (No column name)
-: | :---------------
 1 | obj1
 2 | obj2
 3 | obj3
 4 | obj4  

但我的问题是:

  • 是否有任何隐藏的内置函数可以使用 T-SQL 删除括号?

dbfiddle在这里

sql-server t-sql
  • 4 4 个回答
  • 2639 Views

4 个回答

  • Voted
  1. David Browne - Microsoft
    2018-01-23T08:55:27+08:002018-01-23T08:55:27+08:00

    有时我将对象名称存储在我们的一些数据库中

    我必须注意始终使用或不使用括号来存储这些名称。

    “对象名称”在技术上称为标识符。在某些情况下,标识符将出现在 TSQL 代码中,由 [ 和 ] 或“和”包围。这些字符不是标识符的一部分,您永远不应该存储它们。

    而是将标识符存储为 nvarchar(128)(或 sysname),并在运行时使用QUOTENAME函数添加分隔符。

    QUOTENAME 的倒数是PARSENAME,它具有导航多部分名称的额外能力。

    请注意,QUOTENAME 有一个可选的第二个参数,如果您为该参数指定单引号字符,QUOTENAME 不会创建有效的分隔标识符表达式。它发出一个 varchar 文字表达式。

    • 18
  2. Best Answer
    Paul White
    2018-01-24T03:55:20+08:002018-01-24T03:55:20+08:00

    是否有任何隐藏的内置函数可以使用 T-SQL 删除括号?

    不,不使用 T-SQL。

    OBJECT_ID是一个内在函数。它直接在 SQL Server 可执行代码中实现,而不是在 T-SQL 中;并且它在调用时不调用任何 T-SQL。

    在运行时,通过表达式服务调用获取对象 id sqlmin!I4ObjIdWstr。

    然后,实现会执行所有必要的步骤,将提供的字符串参数解析为引用数据库中对象的 id。

    第一步包括通过处理字符串中的任何分隔标识符sqlmin!CbParseQuotesW。狭义上就是你说的代码函数,但是不能直接从T-SQL访问。它包含以下代码:

    cmp     r9d,22h
    je      sqlmin!CbParseQuotesW+0x185
    cmp     r9d,2Eh
    je      sqlmin!CbParseQuotesW+0x139
    cmp     r9d,5Bh
    je      sqlmin!CbParseQuotesW+0xfe
    cmp     r9d,5Dh
    je      sqlmin!CbParseQuotesW+0xda
    

    ...这是处理字符的测试:

    • 十六进制 22 = 十二月 34 ="
    • 十六进制 2E = 十二月 46 =.
    • 十六进制 5B = 十二月 91 =[
    • 十六进制 5D = 十二月 93 =]

    将参数解析为 id 的其余过程包括:

    • 启动自动只读事务
    • 检查包含的数据库要求
    • 遍历 name 参数的可能匹配项(使用正确的排序规则)
      • 在提供的数据库名称(或当前上下文数据库)中
      • 在提供的架构名称(或sys或用户的默认架构等)中
    • 获取所需的元数据锁
    • 查询元数据缓存以查找匹配项
    • 如有必要,将元数据提取到缓存中
    • 检查权限(访问对象 ID)
    • 返回第一个匹配对象的 id(如果有)

    在旁注中,问题中的代码:

    IF OBJECT_ID('TEST') IS NOT NULL
    

    ...不只是寻找表格。为此,需要使用第二个函数参数。此外,它只查找名为 TEST 的任何模式范围的对象 - 例如,名为 BananaSchema.TEST 的视图将匹配。更好的表达方式是:

    IF OBJECT_ID(N'dbo.TEST', N'U') IS NOT NULL
    

    相关问答:

    • 什么允许 SQL Server 用对象名称交换传递给系统过程的字符串
    • 12
  3. Aaron Bertrand
    2018-01-23T10:46:20+08:002018-01-23T10:46:20+08:00

    SQL Server 显然有一些内部的东西可以去掉[square brackets](或其他标识符,如"double quotes")。

    当您创建一个类似的表时[dbo].[foo],您是对的,它只foo存储在sys.tablesand中sys.objects,并且没有抱怨找不到架构[dbo](带有方括号)。

    但这发生在CREATE TABLE. PARSENAME()正如大卫指出的那样,他们可能正在使用. 连接调试器可以确定,但这有关系吗?

    您可以查看其他地方以查看他们在做什么,sys.sp_rename实际上确实PARSENAME()使用了 yield:

    select @UnqualOldName = parsename(@objname, 1),
            @QualName1 = parsename(@objname, 2),
            @QualName2 = parsename(@objname, 3),
            @QualName3 = parsename(@objname, 4)
    

    但同样,我不确定我是否理解您为什么只想有时删除方括号。

    就我个人而言,我的代码中有足够大比例是为更广泛的受众编写的,他们将在我不知道或无法控制他们是否使用不安全标识符的环境中使用代码。所以我一直并且总是会编写(并且更喜欢)QUOTENAME()用于生成包含任何类型标识符的脚本的代码。

    我宁愿一直把方括号放在那里,也不愿在需要的时候把它们拿走并被咬。

    • 7
  4. jinzai
    2018-01-23T09:56:15+08:002018-01-23T09:56:15+08:00

    当需要方括号时——这是因为您的标识符已经是保留关键字。任意使用它们不仅没有必要,而且如您所见,它会导致很多混乱。

    在我看来,最好的方法是首先避免使用保留标识符。

    • -6

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve