Program Tip

SQL Server 2008 빈 문자열 대 공백

programtip 2020. 10. 12. 08:06
반응형

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 데이터 값에는 데이터 정렬이 있습니다. 데이터 정렬은 각 문자를 나타내는 데 사용되는 비트 패턴, 비교 규칙 및 대소 문자 또는 악센트에 대한 민감도 와 같은 속성을 정의합니다 .

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

Worth noting, too, is that SQL's semantics, where = has to do with the real-world data and the context of the comparison (as opposed to something about bits stored on the computer) has been part of SQL for a long time. The premise of RDBMSs and SQL is the faithful representation of real-world data, hence its support for collations many years before similar ideas (such as CultureInfo) entered the realm of Algol-like languages. The premise of those languages (at least until very recently) was problem-solving in engineering, not management of business data. (Recently, the use of similar languages in non-engineering applications like search is making some inroads, but Java, C#, and so on are still struggling with their non-businessy roots.)

In my opinion, it's not fair to criticize SQL for being different from "most programming languages." SQL was designed to support a framework for business data modeling that's very different from engineering, so the language is different (and better for its goal).

Heck, when SQL was first specified, some languages didn't have any built-in string type. And in some languages still, the equals operator between strings doesn't compare character data at all, but compares references! It wouldn't surprise me if in another decade or two, the idea that == is culture-dependent becomes the norm.


I found this blog article which describes the behavior and explains why.

The SQL standard requires that string comparisons, effectively, pad the shorter string with space characters. This leads to the surprising result that N'' = N' ' (the empty string equals a string of one or more space characters) and more generally any string equals another string if they differ only by trailing spaces. This can be a problem in some contexts.

More information also available in MSKB316626


There was a similar question a while ago where I looked into a similar problem here

Instead of LEN(' '), use DATALENGTH(' ') - that gives you the correct value.

The solutions were to use a LIKE clause as explained in my answer in there, and/or include a 2nd condition in the WHERE clause to check DATALENGTH too.

Have a read of that question and links in there.


To compare a value to a literal space, you may also use this technique as an alternative to the LIKE statement:

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

Sometimes one has to deal with spaces in data, with or without any other characters, even though the idea of using Null is better - but not always usable. I did run into the described situation and solved it this way:

... where ('>' + @space + '<') <> ('>' + @space2 + '<')

Of course you wouldn't do that fpr large amount of data but it works quick and easy for some hundred lines ...

Herbert


How to distinct records on select with fields char/varchar on sql server: example:

declare @mayvar as varchar(10)

set @mayvar = 'data '

select mykey, myfield from mytable where myfield = @mayvar

expected

mykey (int) | myfield (varchar10)

1 | 'data '

obtained

mykey | myfield

1 | 'data' 2 | 'data '

even if I write select mykey, myfield from mytable where myfield = 'data' (without final blank) I get the same results.

how I solved? In this mode:

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

and if there is an index on myfield, it'll be used in each case.

I hope it will be helpful.


Another way is to put it back into a state that the space has value. eg: replace the space with a character known like the _

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

returns: not equal

Not ideal, and probably slow, but is another quick way forward when needed quickly.

참고URL : https://stackoverflow.com/questions/1399844/sql-server-2008-empty-string-vs-space

반응형