SQL Server는 where 표현식에서 대소 문자를 무시합니다.


답변:


137

SQL Server 데이터베이스의 기본 구성에서 문자열 비교 대소 문자를 구분하지 않습니다. 데이터베이스가이 설정을 재정의하는 경우 (대체 데이터 정렬 사용을 통해) 쿼리에 사용할 데이터 정렬 유형을 지정해야합니다.

SELECT * FROM myTable WHERE myField = 'sOmeVal' COLLATE SQL_Latin1_General_CP1_CI_AS

내가 제공 한 데이터 정렬은 단지 예일뿐입니다. SQL Server 데이터 정렬에 대한 자세한 개요는 여기 에서 찾을 수 있습니다 .


확인하기 위해, 이것은 WHERE문장 끝에 한 번만 추가하면되며 모든 WHERE절에 영향을 미칩니다 . 맞습니까?
ashleedawg

답을 알고 싶습니까? 열 값을 UPPER또는 LOWER대소 문자로 변환 한 다음을 사용하여 LIKE검색 하여 성능 문제가 있습니까?
Shaiju T

1
@ashleedawg-좋은 질문입니다. 라인 당 설정 인 것 같습니다.
Leo Gurdian

29

일반적으로 문자열 비교는 대소 문자를 구분하지 않습니다. 데이터베이스가 대소 문자를 구분하도록 구성된 경우 대소 문자를 구분하지 않는 데이터 정렬을 강제로 사용해야합니다.

SELECT balance FROM people WHERE email = 'billg@microsoft.com'
  COLLATE SQL_Latin1_General_CP1_CI_AS 

@AskeB. and Andrejs : 이것은 기술적으로 데이터베이스 구성 문제가 아닙니다. 문자열 비교에 대한 설명 은 내 대답 을 참조하십시오 .
Solomon Rutzky

21

다른 곳에서 다른 해결책을 찾았습니다. 즉, 사용

upper(@yourString)

하지만 여기있는 모든 사람들은 SQL Server에서 어쨌든 대소 문자를 무시하기 때문에 중요하지 않다고 말합니다. 나는 우리 데이터베이스가 대소 문자를 구분한다고 확신합니다.


7
데이터베이스가 대소 문자를 구분할 수 있다는 것은 맞지만, 필요한 경우에도 상당히 비효율적입니다. COLLATE는 사용할 키워드입니다.
mjaggard

1
알려 주셔서 감사합니다, @mjaggard. 나는 당신이나 내 대답에 반대하는 것처럼 보이는 사람이 나와 같은 대답을 검색하고 찾는 나와 같은 사람을 위해 정교하게 설명하기를 바랍니다.
Danny

1
완벽하게 합리적인 설명이므로 찬성했습니다. 데이터 정렬에 너무 많은 오버 헤드가 발생하고 문자열에 데이터 정렬이 이해하지 못하는 문자가있는 경우 어떻게해야합니까? 라틴어 1은 잘못된 인코딩 체계입니다. 문자열에 아포스트로피가 있으면 의미있는 결과를 얻을 수 있기를 바랍니다 (예 : O'Brien).
eggmatters

2
또한 찬성했습니다. 이것이 유용한 경우를 많이 생각할 수 있습니다. 또한 종종 어떤 일을하는 좋은 방법이 여러 가지 있습니다.
Inversus 2013-04-12

1
비교 목적으로 문자열의 대소 문자를 변경하는 것은 일반적으로 좋지 않습니다. 일부 언어의 경우 변환이 왕복하지 않습니다. 즉 LOWER (x)! = LOWER (UPPER (x)).
Ceisc 2016

17

상위 2 개 답변 ( Adam RobinsonAndrejs Cainikovs )은 기술적으로 작동한다는 점에서 다소 정확하지만 설명이 잘못되어 많은 경우 오해의 소지가 있습니다. 예를 들어 SQL_Latin1_General_CP1_CI_AS데이터 정렬은 대부분의 경우 작동하지만 적절한 대 / 소문자를 구분하지 않는 데이터 정렬이라고 가정해서는 안됩니다. 실제로 OP가 대 / 소문자 구분 (또는 바이너리) 데이터 정렬을 사용하여 데이터베이스에서 작동하고 있다는 점을 감안할 때 OP가 너무 많은 설치 (특히 OS에 설치된 모든 데이터)의 기본값 인 데이터 정렬을 사용하지 않는다는 것을 알고 있습니다. 미국 영어를 언어로 사용) : SQL_Latin1_General_CP1_CI_AS. 물론 OP는를 사용할SQL_Latin1_General_CP1_CS_AS있지만 작업 할 때VARCHAR데이터 손실을 초래할 수 있으므로 코드 페이지를 변경하지 않는 것이 중요하며 이는 데이터 정렬의 로케일 / 문화에 의해 제어됩니다 (예 : Latin1_General 대 프랑스어 대 히브리어 등). 아래 9 번 지점을 참조하십시오.

다른 네 가지 대답은 다양한 정도로 잘못되었습니다.

독자가 가장 적절하고 효율적인 선택을 할 수 있도록 여기에서 모든 오해를 명확히 할 것입니다.

  1. 사용하지 마십시오 UPPER(). 그것은 완전히 불필요한 추가 작업입니다. COLLATE절을 사용하십시오 . 두 경우 모두 문자열 비교를 수행해야하지만를 사용하여 UPPER()대문자 매핑이 있는지 확인한 다음 변경해야합니다. 그리고 양쪽에서 이것을해야합니다. 추가는 COLLATE단순히 기본적으로 사용했던 규칙과 다른 규칙 세트를 사용하여 정렬 키를 생성하도록 처리를 지시합니다. 이 테스트 스크립트 (PasteBin) 에서 입증 된 것처럼 COLLATE사용 하는 것이을 사용 하는 것보다 확실히 더 효율적입니다 (또는 해당 단어가 마음에 들면 "성능" ) .UPPER()

    @Danny의 답변에 @Ceisc가 언급 한 문제도 있습니다 .

    일부 언어의 경우 변환이 왕복하지 않습니다. 즉 LOWER (x)! = LOWER (UPPER (x)).

    터키어 대문자 "İ"가 일반적인 예입니다.

  2. 아니요, 데이터 정렬은 데이터베이스 전체 설정이 아닙니다. 적어도이 컨텍스트에서는 그렇지 않습니다. 데이터베이스 수준의 기본 데이터 정렬이 있으며 COLLATE절을 지정하지 않는 변경 및 새로 생성 된 열에 대한 기본값으로 사용되지만 (이 일반적인 오해의 원인 일 가능성이 높습니다), 그렇지 않으면 쿼리에 직접 영향을주지 않습니다. 문자열 리터럴 및 변수를 다른 문자열 리터럴 및 변수와 비교하거나 데이터베이스 수준 메타 데이터를 참조합니다.

  3. 아니요, 데이터 정렬은 쿼리별로 이루어지지 않습니다.

  4. 데이터 정렬은 쿼리가 아닌 조건 자 (예 : 피연산자) 또는 표현식을 기준으로합니다. 그리고 이것은 WHERE절 뿐만 아니라 전체 쿼리에 대해서도 마찬가지입니다 . 여기에는 JOIN, GROUP BY, ORDER BY, PARTITION BY 등이 포함됩니다.

  5. 아니요, 다음과 같은 이유로 VARBINARY(예 :)로 변환하지 마십시오 convert(varbinary, myField) = convert(varbinary, 'sOmeVal').

    1. 이것은 대소 문자를 구분하지 않는 이진 비교입니다 (이 질문이 요구하는 것입니다)
    2. 이진 비교를 원하면 이진 데이터 정렬을 사용하십시오. _BIN2SQL Server 2008 이상을 사용 하는 경우로 끝나는 것을 사용하십시오 . 그렇지 않으면 _BIN. 데이터가 NVARCHAR그렇다면 해당 경우 모두 동일하므로 사용하는 로케일이 중요하지 않으므로 Latin1_General_100_BIN2항상 작동합니다. 데이터가있는 경우 VARCHAR, 당신은 데이터 (예를 들어, 현재 것과 동일한 로케일을 사용해야합니다 Latin1_General, French, Japanese_XJIS로케일이 사용되는 코드 페이지를 결정하고, 코드 페이지를 변경하면 데이터 (예 : 데이터 손실)을 변경할 수 있기 때문에, 등).
    3. 크기를 지정하지 않고 가변 길이 데이터 유형을 사용하면 기본 크기에 의존하며 데이터 유형이 사용되는 컨텍스트에 따라 두 가지 다른 기본값이 있습니다. 문자열 유형의 경우 1 또는 30입니다. CONVERT()그것 과 함께 사용하면 30 기본값이 사용됩니다. 위험은 문자열이 30 바이트를 초과 할 수있는 경우 자동으로 잘리고이 술어에서 잘못된 결과를 얻을 수 있다는 것입니다.
    4. 대소 문자를 구분하는 비교를 원하더라도 이진 데이터 정렬은 대소 문자를 구분 하지 않습니다 (또 다른 매우 일반적인 오해).
  6. 아니요, LIKE항상 대소 문자를 구분하지는 않습니다. 참조되는 열의 데이터 정렬 또는 변수가 문자열 리터럴과 비교되는 경우 데이터베이스의 데이터 정렬 또는 선택적 COLLATE절을 통해 지정된 데이터 정렬을 사용합니다 .

  7. LCASESQL Server 함수가 아닙니다. Oracle 또는 MySQL 인 것으로 보입니다. 아니면 Visual Basic?

  8. 질문의 컨텍스트는 열을 문자열 리터럴과 비교하기 때문에 인스턴스의 데이터 정렬 (종종 "서버"라고 함)이나 데이터베이스의 데이터 정렬이 여기서 직접적인 영향을 미치지 않습니다 . 데이터 정렬은 각 열마다 저장되며 각 열은 다른 데이터 정렬을 가질 수 있으며 이러한 데이터 정렬은 데이터베이스의 기본 데이터 정렬 또는 인스턴스의 데이터 정렬과 동일 할 필요가 없습니다. 물론 인스턴스 데이터 정렬은 데이터베이스를 COLLATE만들 때 절이 지정되지 않은 경우 새로 만든 데이터베이스가 기본 데이터 정렬로 사용할 항목의 기본값 입니다. 마찬가지로 데이터베이스의 기본 데이터 정렬은 COLLATE절이 지정되지 않은 경우 변경되거나 새로 생성 된 열이 사용하는 것 입니다.

  9. 그렇지 않으면 열의 데이터 정렬과 동일한 대소 문자를 구분하지 않는 데이터 정렬을 사용해야합니다. 다음 쿼리를 사용하여 열의 데이터 정렬을 찾습니다 (테이블 이름 및 스키마 이름 변경).

    SELECT col.*
    FROM   sys.columns col
    WHERE  col.[object_id] = OBJECT_ID(N'dbo.TableName')
    AND    col.[collation_name] IS NOT NULL;
    

    그런 다음 바로 변경할 _CS_CI. 그래서, Latin1_General_100_CS_AS될 것입니다 Latin1_General_100_CI_AS.

    열이 이진 데이터 정렬 ( _BIN또는로 끝남 _BIN2)을 사용하는 경우 다음 쿼리를 사용하여 유사한 데이터 정렬을 찾습니다.

    SELECT *
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] LIKE N'{CurrentCollationMinus"_BIN"}[_]CI[_]%';
    

    예를 들어, 열이를 사용하고 있다고 가정하면 다음을 Japanese_XJIS_100_BIN2수행하십시오.

    SELECT *
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] LIKE N'Japanese_XJIS_100[_]CI[_]%';
    

데이터 정렬, 인코딩 등에 대한 자세한 내용은 다음을 참조하십시오. 데이터 정렬 정보


7

아니요, 사용 만 LIKE작동하지 않습니다. LIKE주어진 패턴과 정확히 일치하는 값을 검색합니다. 이 경우 LIKE'someval'이 아닌 'sOmeVal'텍스트 만 찾습니다.

실용적인 솔루션은 LCASE()함수를 사용하는 것입니다. LCASE('sOmeVal')텍스트의 소문자 문자열 'someval'을 가져옵니다. 이 함수를 비교의 양쪽에 사용하면 다음과 같이 작동합니다.

SELECT * FROM myTable WHERE LCASE(myField) LIKE LCASE('sOmeVal')

이 명령문은 두 개의 소문자 문자열을 비교하므로 'sOmeVal'은 'someval'의 다른 모든 표기법과 일치합니다 (예 : 'Someval', 'sOMEVAl'등).


7
_CI가 대조 된 SQL Server 설치의 99.9 %에서 LIKE는 대소 문자를 구분하지 않습니다.
RichardTheKiwi 2010 년

1
요즘 함수는 LOWER라고합니다.
David Brossard

@DavidBrossard와 David Hermanns, 나는 그것이 LCASE()SQL Server에 있었던 적이 없다고 생각합니다 (적어도 내가 볼 수있는 것은 아닙니다). 이 대답은 완전히 다른 RDBMS에 대한 것이라고 생각합니다. 문자열 비교에 대한 설명 은 내 대답 을 참조하십시오 .
Solomon Rutzky

4

다음과 같이 varbinary로 캐스팅하여 대소 문자를 구분하도록 강제 할 수 있습니다.

SELECT * FROM myTable 
WHERE convert(varbinary, myField) = convert(varbinary, 'sOmeVal')

3
이것이 기능적이지만 권장되는 접근 방식은 아닙니다. 정렬 및 문자열 비교를 관리하기위한 데이터 정렬이 있습니다.
Adam Robinson

@AdamRobinson은 "문자열 비교"에 관한 것이 아닙니까?
Fandango68

@ Fandango68 예, 그렇습니다. Adam은 문자열 비교를 할 때 데이터 정렬이 더 좋다고 말합니다.
JLRishe

@ Fandango68이 대답은 여러 수준에서 잘못되었습니다. 자세한 내용은 내 답변 , 특히 포인트 5를 참조하십시오 .
Solomon Rutzky 19

@AdamRobinson 문자열 비교에 대한 설명 은 내 대답 을 참조하십시오 .
Solomon Rutzky

2

어떤 데이터베이스에 있습니까? MS SQL Server에서는 데이터베이스 전체의 설정이거나 COLLATE 키워드를 사용하여 쿼리별로 재정의 할 수 있습니다.


안녕. SQL Server의 경우이 질문이 무엇에 관한 것인지는 데이터베이스 전체 설정이나 쿼리 별 설정이 아닙니다. 자세한 내용은 내 대답 을 참조하십시오.
Solomon Rutzky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.