Есть ли какая-либо (скрытая) встроенная функция в MS-SQL, чтобы заключать в кавычки имена объектов?

12

Иногда я храню имена объектов (идентификаторы) в некоторых наших базах данных, например в некоторых таблицах параметров. Поскольку я выбираю записи из этих таблиц, используя операторы сравнения '=' или '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 здесь

McNets
источник

Ответы:

12

Есть ли скрытая встроенная функция, которая удаляет скобки с помощью T-SQL?

Нет , не использую T-SQL.

OBJECT_IDявляется внутренней функцией. Он реализован непосредственно в исполняемом коде SQL Server, а не в T-SQL; и он не вызывает T-SQL при вызове.

Во время выполнения идентификатор объекта получается через вызов службы выражений sqlmin!I4ObjIdWstr.

Реализация затем проходит все необходимые шаги, чтобы преобразовать предоставленный строковый параметр (и) в идентификатор объекта в указанной базе данных.

Один из первых шагов включает в себя обработку любых идентификаторов с разделителями в строке с помощью 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

... которые являются тестами для обработки символов:

  • hex 22 = Dec 34 = "
  • hex 2E = dec 46 = .
  • гекс 5В = дек 91 = [
  • hex 5D = dec 93 = ]

Остальная часть процесса преобразования параметров в идентификатор включает в себя:

  • Запуск автоматической транзакции только для чтения
  • Проверка требований к базе данных
  • Перебор возможных совпадений для параметра имени (с использованием правильного сопоставления)
    • В предоставленном имени базы данных (или текущей контекстной базе данных)
    • В предоставленном имени схемы (или sys , или схеме пользователя по умолчанию и т. Д.)
  • Взятие необходимых блокировок метаданных
  • Консультирование кеша метаданных для совпадения
  • Выборка метаданных в кеш при необходимости
  • Проверка разрешений (для доступа к идентификатору объекта)
  • Возврат идентификатора первого сопоставленного объекта (если есть)

На заметку, код в вопросе:

IF OBJECT_ID('TEST') IS NOT NULL

... не ищет только таблицы. Для этого потребуется использовать второй параметр функции. Кроме того, он ищет только любой объект в области схемы с именем TEST - так, например, будет соответствовать представление с именем BananaSchema.TEST. Лучшее выражение будет:

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

Связанные вопросы и ответы:

Пол Уайт 9
источник
18

Иногда я храню имена объектов в некоторых наших базах данных

Я должен заботиться о том, чтобы хранить эти имена всегда с или без скобок.

«Имя объекта» технически называется идентификатором . В некоторых контекстах идентификатор будет появляться в коде TSQL, окруженном [и] или «и». Эти символы не являются частью идентификатора, и вы никогда не должны их хранить.

Вместо этого сохраните идентификатор как nvarchar (128) (или sysname) и добавьте разделители во время выполнения, используя функцию QUOTENAME .

Инверсия QUOTENAME - PARSENAME , которая имеет дополнительную возможность навигации по именам , состоящим из нескольких частей.

Обратите внимание, что QUOTENAME имеет необязательный второй параметр, и, если вы указываете одиночный символ кавычки для этого параметра, QUOTENAME не создает допустимое выражение идентификатора с разделителями. Это испускает буквальное выражение varchar.

Дэвид Браун - Microsoft
источник
7

SQL Server имеет , очевидно, что - то внутреннее , что обрезает [square brackets](или другие идентификаторы, например "double quotes").

Когда вы создаете таблицу как [dbo].[foo], вы правы, только fooсохраняется в sys.tablesи sys.objects, и нет никаких претензий, что схема [dbo](с квадратными скобками) не была найдена.

Но это происходит внутри кода для CREATE TABLE. Они могут использовать PARSENAME(), как указал Дэвид. Подключение отладчика может указывать наверняка, но имеет ли это значение?

Вы можете посмотреть в другом месте, чтобы увидеть, что они делают, и sys.sp_renameна самом деле дает результат, который PARSENAME()используется:

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

Но опять же, я не уверен, что понимаю, почему вы хотите только иногда снимать квадратные скобки.

Лично для меня достаточно большой процент моего кода написан для более широкой аудитории, которая будет использовать код в средах, где я не знаю и не контролирую, используют ли они небезопасные идентификаторы. Поэтому я всегда имею и всегда буду писать (и предпочитаю) код, который используется QUOTENAME()для генерации сценариев, которые включают в себя любые идентификаторы.

Я бы предпочел иметь квадратные скобки там все время, чем убрать их и укусить один раз, когда они были необходимы.

Аарон Бертран
источник
2
@McNets - Для небольшого числа случаев, когда это может быть полезно, я бы предпочел, чтобы они сосредоточились на других вещах. Вы можете довольно легко использовать существующие функции строки содрать передней и задней [и ]заменить любой ]]с]
Мартин Смит
-6

Когда нужны квадратные скобки - это потому, что ваш идентификатор уже является зарезервированным ключевым словом. Их произвольное использование не только не обязательно, но и приводит к путанице, как вы можете видеть.

На мой взгляд, лучше всего избегать использования зарезервированных идентификаторов.

jinzai
источник