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고유 함수. T-SQL이 아닌 SQL Server 실행 코드로 직접 구현됩니다. 호출 될 때 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

... 문자를 처리하는 테스트입니다.

  • 16 진 22 = 12 월 34 = "
  • 육각 2E = 12 월 46 = .
  • 육각 5B = 12 월 91 = [
  • 육각 5D = 12 월 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

관련 Q & A :


18

때로는 일부 데이터베이스에 객체 이름을 저장합니다.

항상 대괄호를 사용하거나 사용하지 않고이 이름을 저장해야합니다.

"객체 이름"을 기술적으로 식별자 라고합니다 . 일부 상황에서 식별자는 [와] 또는 "와"로 둘러싸인 TSQL 코드로 나타납니다. 이러한 문자는 식별자의 일부가 아니므로 절대 저장하지 않아야합니다.

대신 식별자를 nvarchar (128) (또는 sysname)로 저장하고 QUOTENAME 함수를 사용하여 런타임에 구분 기호를 추가하십시오 .

QUOTENAME의 역은 PARSENAME 이며, 이는 여러 부분으로 구성된 이름을 탐색하는 추가 기능이 있습니다.

QUOTENAME에는 선택적 두 번째 매개 변수가 있으며 해당 매개 변수에 작은 따옴표를 지정하면 QUOTENAME은 유효한 구분 식별자 표현식을 작성하지 않습니다. varchar 리터럴 표현식을 내 보냅니다.


7

SQL Server에는 분명히 내부적으로 무언가 가 제거되어 있습니다 [square brackets]( 또는와 같은 다른 식별자 "double quotes").

와 같은 테이블을 만들면 [dbo].[foo]옳고 and 만 foo저장되며 스키마 (대괄호 포함)를 찾을 수 없다는 불만 은 없습니다.sys.tablessys.objects[dbo]

그러나 이것은의 코드 내부에서 발생합니다 CREATE TABLE. PARSENAME()David가 지적한 것처럼을 사용 하고 있을 수 있습니다 . 디버거를 연결하면 확실히 알 수 있지만 중요합니까?

그들이 무엇을하고 있는지 알기 위해 다른 곳을 볼 수 있으며, 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

대괄호가 필요한 경우 식별자는 이미 예약 된 키워드이기 때문입니다. 그것들을 임의로 사용하는 것은 필요하지 않을뿐만 아니라, 당신이 볼 수 있듯이 많은 혼란을 초래합니다.

내 의견으로는, 가장 좋은 방법은 우선 예약 식별자를 사용하지 않는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.