2016-11-15 2 views
3

많은 프로그래밍 언어에서>,> =, < 등과 같은 연산자를 사용하여 문자열을 비교할 수 있으며, 언어는 알파벳의 문자 위치에 대한 비교를 기반으로합니다. 포스트 그레스 또는 MySQL의비교 연산자를 사용하여 포스트그레스의 문자열 비교?

SELECT 
CASE WHEN 'a' < 'b' THEN 'yes' END 
FROM table 
Output: null 

에서 그러나

if ('a' < 'b') { 
    echo 'Yes'; 
} else { 
    echo 'No'; 
} 
> Yes 

PHP

예를 들어

나는 SQL을 통해 서로 비교해야 문자열 테이블을 가지고있다. 예를 들어

: 6.2 (5A) 6.2 (5B) - (5A)

이 6.2보다 큰 것 -이 또는 6.2 (15) 6.2 (5A)보다 큰 것이다 나는 정규 표현식을 사용하여 문자에 숫자를 할당하는 것을 고려했다. 그러나 그 문자가 없을 때 비교를 깨뜨릴 것이다.

순전히 SQL에 대해 어떻게 생각하십니까?

+0

'select'a '<'b ';'는 postgres 9.6.1에서 True로 표시됩니다. 6.2 (5a) '<'6.2 (5b) ';는 참을 반환한다. 6.2 (15) '<'6.2 (5a) '; 또한 True를 반환합니다. 마지막 문자는'6.2 ('일치하고 다음 문자''1 '<'5''과 6.2 (15)가 6.2 (5a)보다 작기 때문에 사실입니다.) – zedfoxus

+0

사실 그게 사실입니다. '6.2 (15)'<6.2 (5a)>가 실제로 돌아 왔음을 알리는 후자의 비교는 당신이 그것을 지적하기 전까지는 알지 못했다. '15'는 '5a'보다 더 큽니다. 먼저 문자를 테스트하고 제거하고 숫자 문자열을 테스트 할 수 있습니까? – bakamike

+0

[PostgreSQL ORDER BY 발행물 - 자연 정렬] 가능한 중복 (http://stackoverflow.com/questions/9173558)/postgresql-order-by-issue-natural-sort) – Schwern

답변

5

대부분의 문자열 비교는 기본적으로 ASCIIbetical sorting으로 알려져 있습니다. 각 문자를 ASCII 번호 (또는 처음 7 비트는 ASCII와 겹치는 UTF-8)로 변환 한 다음 정렬합니다. 이 은 ... 잘 정렬 보인다

select 'a' < 'z'; -- true 

...하지만 빨리 잘못.

select 'a' < 'Z'; -- false 

대문자가 모두 ASCII의 모든 소문자와 UTF-8 뒤에 있기 때문입니다.

간단한 수정 방법은 양쪽에서 upper 또는 lower을 호출하여 사례를 표준화하는 것입니다. ASCIIbetical 정렬과

select lower('a') < lower('Z'); -- true 

두 번째 문제는 숫자입니다. 다시, 그것은 밖으로 시작됩니다 ...

select 'a9' < 'a1'; -- true 

...하지만 빠르게 냄비에 간다.

select 'a9' < 'a10'; -- false 

ASCIIbetical 정렬은 한 번에 한 문자 씩 비교합니다. ASCII 9 (57)는 ASCII 1 (49)보다 작습니다.


은 당신이 원하는 것은 문자열과 숫자는 숫자로 비교로 문자열 부분이 비교되는 natural sort이다. SQL에서 자연 정렬을하는 것은 쉬운 일이 아닙니다. 각각의 부분 문자열을 개별적으로 정렬하기 위해 고정 된 필드 너비가 필요하거나 정규식을 사용하여 뭔가를 정렬 할 필요가 있습니다 ...

다행히도 효율적인 자연 정렬을 구현하는 Postgres 확장자가 pg_natural_sort_order입니다.

확장 프로그램을 설치할 수없는 경우 btrsort by 2kan과 같은 저장 프로 시저를 사용할 수 있습니다.

CREATE FUNCTION btrsort_nextunit(text) RETURNS text AS $$ 
    SELECT 
     CASE WHEN $1 ~ '^[^0-9]+' THEN 
      COALESCE(SUBSTR($1, LENGTH(SUBSTRING($1 FROM '[^0-9]+'))+1), '') 
     ELSE 
      COALESCE(SUBSTR($1, LENGTH(SUBSTRING($1 FROM '[0-9]+'))+1), '') 
     END 

$$ LANGUAGE SQL; 

CREATE FUNCTION btrsort(text) RETURNS text AS $$ 
    SELECT 
     CASE WHEN char_length($1)>0 THEN 
      CASE WHEN $1 ~ '^[^0-9]+' THEN 
       RPAD(SUBSTR(COALESCE(SUBSTRING($1 FROM '^[^0-9]+'), ''), 1, 12), 12, ' ') || btrsort(btrsort_nextunit($1)) 
      ELSE 
       LPAD(SUBSTR(COALESCE(SUBSTRING($1 FROM '^[0-9]+'), ''), 1, 12), 12, ' ') || btrsort(btrsort_nextunit($1)) 
      END 
     ELSE 
      $1 
     END 
     ; 
$$ LANGUAGE SQL; 

비록 비교 연산자를 제공하지는 않지만 그것을 이해하는 척하지는 않을 것입니다. 이를 통해 order by에서 사용할 수 있습니다.

select * from things order by btrsort(whatever); 

는, 큰 테이블에 진흙 you can create a btree index on the result of that function 회전에서 자연적으로 분류 쿼리를 방지합니다.

create index things_whatever_btrsort_idx ON things(btrsort(whatever)); 
+0

불행히도 greenplum과 닫힌 시스템에서 실행되는 postgres입니다. 확장자를 설치할 수 없습니다. – bakamike

+0

@bakamike 저장 프로 시저를 사용하는 대안을 추가했습니다. . – Schwern