Как диапазон подстановочных знаков SQL Server, например [A-D], работает с сортировкой с учетом регистра? - PullRequest
9 голосов
/ 07 декабря 2011

Может кто-нибудь объяснить правила того, как диапазон символов подстановки, например, [AD], работает с сортировкой с учетом регистра?

Я бы подумал, что следующее

WHERE CharColumn LIKE '[A-D]%';

будетвозвращать только записи, которые начинаются с заглавных букв A, B, C или D, и исключать записи, начинающиеся с строчных букв a, b, c или d.

Однако в действительности кажется, что они возвращают записикоторые начинаются с верхнего регистра A, но также и записи, которые начинаются с B или b, C или c и D или d.Как будто только первый символ диапазона чувствителен к регистру, а остальные символы в диапазоне не чувствительны к регистру.

С другой стороны, следующее

WHERE CharColumn LIKE '[ABCD]%';

возвращает только те записи, которые начинаются с прописных букв A, B, C или D. И все же я быдумал, что [AD] будет эквивалентно [ABCD].

Я получаю те же результаты в SQL Server 2005 и SQL Server 2008 R2.

Пример:
(вставьте операторы, написанные с использованием SQLКонструкторы строк Server 2008 для компактности. Если каждому значению присваивается свой оператор вставки, сценарий будет работать в SQL Server 2005)

CREATE TABLE #TEST_LIKE_Patterns
    ( 
        ID INT IDENTITY(1,1),
        CharColumn VARCHAR(100) COLLATE Latin1_General_CS_AS
    );

--------------
INSERT INTO #TEST_LIKE_Patterns (CharColumn)
VALUES ('aaa'), ('aAA'), ('AAA'), ('Aaa');
--------------    
INSERT INTO #TEST_LIKE_Patterns (CharColumn)
VALUES ('bbb'), ('bBB'), ('BBB'), ('Bbb');
--------------
INSERT INTO #TEST_LIKE_Patterns (CharColumn)
VALUES ('ccc'), ('cCC'), ('CCC'), ('Ccc');
--------------    
INSERT INTO #TEST_LIKE_Patterns (CharColumn)
VALUES ('ddd'), ('dDD'), ('DDD'), ('Ddd');
--------------    
INSERT INTO #TEST_LIKE_Patterns (CharColumn)
VALUES ('eee'), ('eEE'), ('EEE'), ('Eee');
--------------    
INSERT INTO #TEST_LIKE_Patterns (CharColumn)
VALUES ('fff'), ('fFF'), ('FFF'), ('Fff');
--------------

-- Raw Data:
SELECT *
FROM #TEST_LIKE_Patterns;

SELECT *
FROM #TEST_LIKE_Patterns
WHERE CharColumn LIKE '[A-D]%';

-- Results:
/*
ID   CharColumn
--------------
3    AAA
4    Aaa
5    bbb
6    bBB
7    BBB
8    Bbb
9    ccc
10   cCC
11   CCC
12   Ccc
13   ddd
14   dDD
15   DDD
16   Ddd
*/


SELECT *
FROM #TEST_LIKE_Patterns
WHERE CharColumn LIKE '[ABCD]%';    

-- Results:
/*
ID   CharColumn
    --------------
3    AAA
4    Aaa
7    BBB
8    Bbb
11   CCC
12   Ccc
15   DDD
16   Ddd
*/

Ответы [ 4 ]

11 голосов
/ 07 декабря 2011

Вам нужно двоичное сопоставление, как указано в Md.Ответ Элиаса Хоссейна .

Объяснение состоит в том, что диапазоны в синтаксисе шаблона работают от правил сортировки сортировки.

От BOL

При поиске по диапазону символы, включенные в диапазон, могут различаться в зависимости от правил сортировки.

Итак

;WITH T(C) AS
(
SELECT 'A' UNION ALL
SELECT 'B' UNION ALL
SELECT 'C' UNION ALL
SELECT 'D' UNION ALL
select 'a' union all
select 'b' union all
select 'c' union all
select 'd'
)
SELECT *
FROM T
ORDER BY C COLLATE Latin1_General_CS_AS

Возвращает

C
----
a
A
b
B
c
C
d
D

Таким образом, диапазон A-D исключает a, но включает в себя другие 3 строчные буквы в сопоставлении CS.

10 голосов
/ 07 декабря 2011

Это можно сделать любым способом:

a.Используйте COLLATE при создании таблицы как:

CREATE TABLE #TEST_LIKE_Patterns
( 
    ID INT IDENTITY(1,1),
    CharColumn VARCHAR(100) COLLATE Latin1_General_BIN
);

b.Используйте COLLATE при выборе данных как

SELECT *
FROM #TEST_LIKE_Patterns
WHERE CharColumn LIKE '%[A-D]%' COLLATE Latin1_General_BIN;
3 голосов
/ 07 декабря 2011

1001 * попробовать *

SELECT *
FROM #TEST_LIKE_Patterns
WHERE CharColumn  LIKE '[A-D]%' COLLATE Latin1_General_BIN;
0 голосов
/ 07 декабря 2011

Использование сортировки с учетом регистра работает для строк поиска, которые не находятся в диапазоне, например, это будет работать:

SELECT *
  FROM #TEST_LIKE_Patterns
 WHERE (
        CharColumn LIKE 'A%' COLLATE Latin1_General_CS_AS
        OR CharColumn LIKE 'B%' COLLATE Latin1_General_CS_AS
        OR CharColumn LIKE 'C%' COLLATE Latin1_General_CS_AS
        OR CharColumn LIKE 'D%' COLLATE Latin1_General_CS_AS
       );

... но очевидно, что это неприемлемый подход!

Как предлагали другие, используйте Latin1_General_BIN для диапазонов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...