[0-9]와 같이 숫자가 아닌 이유는 무엇입니까?


13

이 쿼리에 따라 서버의 기본 데이터 정렬은 Latin1_General_CI_AS입니다.

SELECT SERVERPROPERTY('Collation') AS Collation;

이 데이터 정렬을 사용하면 술어를 사용하여 문자열의 숫자가 아닌 문자를 일치시킬 수 있다는 사실에 놀랐습니다 LIKE '[0-9]'.

기본 데이터 정렬에서 왜 이런 일이 발생합니까? 이것이 유용한 경우를 생각할 수 없습니다. 이진 데이터 정렬을 사용하여 문제를 해결할 수 있지만 기본 데이터 정렬을 구현하는 이상한 방법처럼 보입니다.

숫자를 필터링하면 숫자가 아닌 카락 터가 생성됩니다.

가능한 모든 1 바이트 문자 값을 포함하는 열을 작성하고 숫자 일치 술어로 값을 필터링하여 동작을 시연 할 수 있습니다.

다음 명령문은 현재 코드 페이지의 각 코드 포인트마다 하나씩 256 개의 행이있는 임시 테이블을 작성합니다.

WITH P0(_) AS (SELECT 0 UNION ALL SELECT 0),
P1(_) AS (SELECT 0 FROM P0 AS L CROSS JOIN P0 AS R),
P2(_) AS (SELECT 0 FROM P1 AS L CROSS JOIN P1 AS R),
P3(_) AS (SELECT 0 FROM P2 AS L CROSS JOIN P2 AS R),
Tally(Number) AS (
  SELECT -1 + ROW_NUMBER() OVER (ORDER BY (SELECT 0))
  FROM P3
)
SELECT Number AS CodePoint, CHAR(Number) AS Symbol
INTO #CodePage
FROM Tally
WHERE Number >= 0 AND Number <= 255;

각 행에는 코드 포인트의 정수 값과 코드 포인트의 문자 값이 포함됩니다. 모든 문자 값을 표시 할 수있는 것은 아닙니다. 일부 코드 포인트는 엄격하게 제어 문자입니다. 다음은 출력에 대한 선택적 샘플입니다 SELECT CodePoint, Symbol FROM #CodePage.

0   
1   
2   
...
32   
33  !
34  "
35  #
...
48  0
49  1
50  2
...
65  A
66  B
67  C
...
253 ý
254 þ
255 ÿ

LIKE 술어를 사용하고 '0'에서 '9'까지의 문자 범위를 지정하여 숫자 문자를 찾기 위해 기호 열을 필터링 할 수있을 것으로 기대합니다.

SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]';

놀라운 출력을 생성합니다.

CodePoint   Symbol
48  0
49  1
50  2
51  3
52  4
53  5
54  6
55  7
56  8
57  9
178 ²
179 ³
185 ¹
188 ¼
189 ½
190 ¾

48에서 57까지의 코드 포인트 세트가 내가 기대하는 것입니다. 놀랍게도 위첨자와 분수 기호가 결과 세트에 포함되어 있다는 것입니다!

지수와 분수를 숫자로 생각하는 수학적 이유가있을 수 있지만 숫자라고 부르는 것은 잘못된 것 같습니다.

이진 데이터 정렬을 해결 방법으로 사용

나는 내가 기대하는 결과를 얻기 위해 해당 이진 데이터 정렬 Latin1_General_BIN을 강제 할 수 있음을 이해합니다.

SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]' COLLATE Latin1_General_BIN;

결과 집합에는 48 ~ 57 사이의 코드 포인트 만 포함됩니다.

CodePoint   Symbol
48  0
49  1
50  2
51  3
52  4
53  5
54  6
55  7
56  8
57  9

답변:


22

[0-9] 숫자 만 일치하도록 정의 된 정규식 유형이 아닙니다.

LIKE패턴의 모든 범위는 데이터 정렬 순서에 따라 시작 문자와 끝 문자 사이의 문자와 일치합니다.

SELECT CodePoint,
       Symbol,
       RANK() OVER (ORDER BY Symbol COLLATE Latin1_General_CI_AS) AS Rnk
FROM   #CodePage
WHERE  Symbol LIKE '[0-9]' COLLATE Latin1_General_CI_AS
ORDER  BY Symbol COLLATE Latin1_General_CI_AS 

보고

CodePoint            Symbol Rnk
-------------------- ------ --------------------
48                   0      1
188                  ¼      2
189                  ½      3
190                  ¾      4
185                  ¹      5
49                   1      5
50                   2      7
178                  ²      7
179                  ³      9
51                   3      9
52                   4      11
53                   5      12
54                   6      13
55                   7      14
56                   8      15
57                   9      16

당신 때문에 이러한 문자 종류 후 기본 데이터 정렬에서 이러한 결과를 얻을 수 있도록 0하지만, 전 9.

데이터 정렬이 사이의 올바른 순서로 분수와 수학 위해 실제로 일종의 그들에게 정의 된 것처럼 보입니다 0하고 1.

범위 대신 세트를 사용할 수도 있습니다. 2일치 하지 않으려면 데이터 정렬 ²이 필요합니다.CS

SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0123456789]' COLLATE Latin1_General_CS_AS

6

Latin1은 코드 페이지 1252이며 178은 'SUPERSCRIPT TWO' 입니다. 이것은 유니 코드 위첨자입니다 : 위첨자로 문자 "2" 입니다. 유니 코드 기술 표준 # 10 에 따르면 2와 동일하게 비교해야합니다. 8.1 데이터 정렬 접기를 참조하십시오 .

전각 및 위 첨자 문자와 같은 호환성 (3 차) 등가물 을 대표 문자로 매핑

버그 2는 위첨자 2가 2와 다른 경우입니다! '하지만 내 열이 유니 코드가 아닙니다'라고 말하기 전에 안심하십시오. MSDN (Windows 데이터 정렬 참조) 에 따르면 모든 문자열 비교 및 ​​정렬은 온 디스크 표현이 CHAR 인 경우에도 유니 코드 규칙에 따라 수행됩니다.

귀하의 예에서 다른 문자들에 관해서는, 같은 문자들은 VULGAR FRACTION ONE QUARTER숫자와 같지 않지만 Mark가 이미 보여준 것처럼 0과 9 사이에서 올바르게 정렬됩니다.

물론 코드 페이지를 변경하면 다른 결과를 얻을 수 있습니다. 예 : 와 Greek_CS_AS( 코드 페이지 1253 ) 당신은 코드 178, 179 및 189로 문자를 얻을 것입니다.

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