Чи є яка-небудь (прихована) вбудована функція в 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 тут

Відповіді:


12

Чи є яка-небудь прихована вбудована функція, яка видаляє дужки за допомогою T-SQL?

Ні , не використовується T-SQL.

OBJECT_IDє внутрішньою функцією. Він реалізований безпосередньо у виконуваному коді SQL Server, а не в T-SQL; і при виклику він не викликає жодного T-SQL.

Під час виконання ідентифікатор об'єкта отримується через виклик служби вираження sqlmin!I4ObjIdWstr.

Потім реалізація проходить усі необхідні кроки для вирішення наданих рядкових параметрів (ів) в ідентифікатор об'єкта в посилається на базу даних.

Один з перших кроків включає обробку будь-яких обмежених ідентифікаторів у рядку via 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 = "
  • hex 2E = dec 46 = .
  • шістнадцятковий 5B = dec 91 = [
  • шістнадцятковий 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

Питання та відповіді:


18

Іноді я зберігаю назви об’єктів у деяких наших базах даних

Я повинен подбати про збереження цих імен завжди з дужками або без них.

"Ім'я об'єкта" технічно називається ідентифікатором . У деяких контекстах ідентифікатором з'явиться код TSQL, оточений [і] або "і". Ці символи не є частиною ідентифікатора, і їх ніколи не слід зберігати.

Замість цього зберігайте ідентифікатор як nvarchar (128) (або sysname) та додайте роздільники під час виконання за допомогою функції QUOTENAME .

Зворотною стороною QUOTENAME є PARSENAME , яка має додаткову можливість орієнтуватися на багаточастинні імена.

Зауважте, що QUOTENAME має необов'язковий другий параметр, і якщо ви вказали єдиний символ цитати для цього параметра, QUOTENAME не створює дійсного вираженого обмеженого ідентифікатора. Він випромінює вархар буквальний вираз.


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

Коли потрібні квадратні дужки - це тому, що ваш ідентифікатор вже зарезервоване ключове слово. Використовувати їх довільно не тільки не потрібно, це призводить до великої плутанини, як ви бачите.

На мою думку, найкращий спосіб - у першу чергу уникнути використання зарезервованих ідентифікаторів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.