[sql-server] SQL Server 2008 빈 문자열 대 공백

나는 오늘 아침에 약간 이상한 일을 만났고 해설을 위해 제출할 것이라고 생각했습니다.

누군가 SQL 2008에 대해 실행할 때 다음 SQL 쿼리가 ‘동일’을 인쇄하는 이유를 설명 할 수 있습니까? db 호환성 수준은 100으로 설정되어 있습니다.

if '' = ' '
    print 'equal'
else
    print 'not equal'

그리고 이것은 0을 반환합니다.

select (LEN(' '))

공간을 자동 트리밍하는 것 같습니다. 이전 버전의 SQL Server에서 이런 경우인지 알 수 없으며 더 이상 테스트 할 수 없습니다.

프로덕션 쿼리가 잘못된 결과를 반환했기 때문에이 문제가 발생했습니다. 이 동작은 문서화 된 곳에서 찾을 수 없습니다.

누구든지 이것에 대한 정보가 있습니까?



답변

varchars와 평등은 TSQL에서 까다 롭습니다. 이 LEN기능은 다음과 같이 말합니다.

후미 공백을 제외한 주어진 문자열 표현식의 바이트 수가 아닌 문자 수를 반환합니다 .

문제가되는 데이터 DATALENGTH의 실제 byte개수 를 얻으려면 을 사용해야 합니다 . 유니 코드 데이터가있는 경우이 상황에서 얻는 값은 텍스트 길이와 동일하지 않습니다.

print(DATALENGTH(' ')) --1
print(LEN(' '))        --0

식의 동등성에 관해서는 다음과 같이 두 문자열이 동등성을 비교합니다.

  • 더 짧은 문자열 가져 오기
  • 길이가 긴 문자열과 같아 질 때까지 공백으로 채 웁니다.
  • 두 가지 비교

예상치 못한 결과를 초래하는 중간 단계입니다. 그 단계 후에는 공백과 공백을 효과적으로 비교하므로 동일한 것으로 보입니다.

LIKE=일치시키려는 패턴에서 공백 채우기를 수행하지 않기 때문에 “공백”상황에서 보다 더 잘 작동합니다 .

if '' = ' '
print 'eq'
else
print 'ne'

줄 것입니다 eq:

if '' LIKE ' '
print 'eq'
else
print 'ne'

줄게 ne

주의 LIKE: 대칭 적이 지 않습니다. 후행 공백을 패턴 (RHS)에서 중요한 것으로 처리하지만 일치 표현식 (LHS)은 처리하지 않습니다. 다음은 여기 에서 가져온 것입니다 .

declare @Space nvarchar(10)
declare @Space2 nvarchar(10)

set @Space = ''
set @Space2 = ' '

if @Space like @Space2
print '@Space Like @Space2'
else
print '@Space Not Like @Space2'

if @Space2 like @Space
print '@Space2 Like @Space'
else
print '@Space2 Not Like @Space'

@Space Not Like @Space2
@Space2 Like @Space


답변

= 연산자는 T-SQL이 “표현식 컨텍스트의 데이터 정렬에 따라 동일한 단어 / 구문”이기 때문에 “같지 않음”이고 LEN은 “단어 / 구문의 문자 수”입니다. 데이터 정렬은 후행 공백을 선행하는 단어 / 구문의 일부로 처리하지 않습니다 (단, 선행 공백을 선행하는 문자열의 일부로 처리 함).

‘this’와 ‘this’를 구분해야하는 경우 ‘this’와 ‘this’는 같은 단어이므로 “같은 단어 또는 구문입니다”연산자를 사용하지 마십시오.

= works 방식에 기여하는 것은 문자열 같음 연산자가 인수의 내용과 표현식의 데이터 정렬 컨텍스트에 의존해야한다는 생각이지만, 둘 다 문자열 유형 인 경우 인수의 유형에 의존해서는 안됩니다. .

“이것들은 같은 단어입니다”라는 자연어 개념은 일반적으로 =와 같은 수학적 연산자로 캡처 할 수있을만큼 정확하지 않으며 자연어에는 문자열 유형 개념이 없습니다. 문맥 (즉, 대조)은 중요하고 (자연어로 존재) 스토리의 일부이며, 추가 속성 (일부 기발 해 보이는)은 =의 부 자연스러운 세계에서 잘 정의되도록 정의의 일부입니다. 데이터.

유형 문제에서 단어가 다른 문자열 유형에 저장 될 때 변경되는 것을 원하지 않을 것입니다. 예를 들어, VARCHAR (10), CHAR (10) 및 CHAR (3) 유형은 모두 ‘cat’및?라는 단어의 표현을 보유 할 수 있습니다. = ‘cat’은 이러한 유형의 값이 ‘cat’이라는 단어를 포함하는지 여부를 결정하도록해야합니다 (대소 문자 및 악센트 문제는 데이터 정렬에 의해 결정됨).

JohnFx의 의견에 대한 응답 :

보다 온라인 설명서에서 char 및 varchar 데이터 사용을 . 그 페이지에서 인용하면 다음과 같습니다.

각 char 및 varchar 데이터 값에는 데이터 정렬이 있습니다. 데이터 정렬은 각 문자를 나타내는 데 사용되는 비트 패턴과 같은 속성을 정의합니다.
비교 규칙 및 대소 문자 또는 악센트에 대한 민감도.

찾기가 더 쉬울 수 있다는 데 동의하지만 문서화되어 있습니다.

또한 주목할 가치가있는 것은 =가 실제 데이터와 관련이있는 SQL의 의미 체계와 비교 컨텍스트 (컴퓨터에 저장된 비트에 대한 내용과 반대)가 오랫동안 SQL의 일부 였다는 것입니다. RDBMS와 SQL의 전제는 실제 데이터를 충실하게 표현하는 것이므로 유사한 아이디어 (예 : CultureInfo)가 Algol과 유사한 언어 영역에 진입하기 수년 전에 데이터 정렬을 지원합니다. 이러한 언어의 전제는 비즈니스 데이터 관리가 아니라 엔지니어링 문제 해결이었습니다. (최근에는 검색과 같은 비 엔지니어링 애플리케이션에서 유사한 언어를 사용하는 것이 일부 확산되고 있지만 Java, C # 등은 여전히 ​​비업무 적 뿌리에서 어려움을 겪고 있습니다.)

제 생각에는 SQL이 “대부분의 프로그래밍 언어”와 다르다고 비판하는 것은 공정하지 않습니다. SQL은 엔지니어링과는 매우 다른 비즈니스 데이터 모델링을위한 프레임 워크를 지원하도록 설계되었으므로 언어가 다르며 목표에 더 적합합니다.

SQL이 처음 지정되었을 때 일부 언어에는 기본 제공 문자열 유형이 없었습니다. 그리고 일부 언어에서는 여전히 문자열 사이의 같음 연산자가 문자 데이터를 전혀 비교하지 않고 참조를 비교합니다! 앞으로 10 ~ 20 년 후에 ==가 문화에 의존한다는 생각이 표준이된다면 놀라지 않을 것입니다.


답변

나는 행동을 설명하고 그 이유를 설명하는 이 블로그 기사 를 찾았습니다 .

SQL 표준에서는 문자열 비교를 통해 더 짧은 문자열을 공백 문자로 효과적으로 채워야합니다.
이로 인해 N ”= N ”(빈 문자열은 하나 이상의 공백 문자로 구성된 문자열과 동일)이라는 놀라운 결과가 발생하고, 후행 공백 만 다른 경우 더 일반적으로 모든 문자열은 다른 문자열과 같습니다. 이는 일부 상황에서 문제가 될 수 있습니다.

MSKB316626 에서도 더 많은 정보를 볼 수 있습니다.


답변

얼마 전에 비슷한 문제를 여기에서 조사한 비슷한 질문이있었습니다.

대신 올바른 값을 제공 LEN(' ')하는 DATALENGTH(' ')-를 사용 하십시오.

해결책은 LIKE거기에 내 대답에 설명 된 절 을 사용 하고 / 또는 WHERE절에 두 번째 조건을 포함 하여 확인하는 것이 었습니다.DATALENGTH 습니다.

그 질문과 링크를 읽으십시오.


답변

값을 리터럴 공간과 비교하려면 LIKE 문 대신이 기술을 사용할 수도 있습니다.

IF ASCII('') = 32 PRINT 'equal' ELSE PRINT 'not equal'


답변

SQL Server에서 char / varchar 필드를 사용하여 선택시 레코드를 구별하는 방법 : 예 :

declare @mayvar as varchar(10)

set @mayvar = 'data '

select mykey, myfield from mytable where myfield = @mayvar

예상

mykey (int) | myfield (varchar10)

1 | ‘데이터’

획득

mykey | Myfield

1 | ‘데이터’
2 | ‘데이터’

내가 써도
select mykey, myfield from mytable where myfield = 'data'(마지막 공백없이) 같은 결과를 얻습니다.

내가 어떻게 해결 했어? 이 모드에서 :

select mykey, myfield
from mytable
where myfield = @mayvar
and DATALENGTH(isnull(myfield,'')) = DATALENGTH(@mayvar)

myfield에 인덱스가있는 경우 각 경우에 사용됩니다.

도움이 되었으면합니다.


답변

또 다른 방법은 공간에 가치가있는 상태로 되 돌리는 것입니다. 예 : 공백을 _와 같은 문자로 대체하십시오.

if REPLACE('hello',' ','_') = REPLACE('hello ',' ','_')
    print 'equal'
else
    print 'not equal'

반환 : 같지 않음

이상적이지 않고 느릴 수도 있지만 빠르게 필요할 때 앞으로 나아가는 또 다른 빠른 방법입니다.