티스토리 뷰

GPT야 썸네일 좀 잘 뽑아봐..

 

개요

기본적으로 컨텐츠 정렬은 등록일자의 역순이 일반적이다. 그런데 정책 요구사항으로 이름 순 정렬이 생겼다.

 

이름 순 정렬이니 별생각없이 컬럼 정렬로 order by name ASC를 한다면? 재미있는 일을 마주하게 된다.

 

가장 먼저 숫자 쪽에서 의도치 않은 동작을 확인하게 된다.

1 5 10 20 100 1100

 위와 같은 순서로 이름을 짓게 되면 아래와 같이 정렬이 된다.

1 10 100 1100 20 5

이건 가장 단편적으로 보이는 문제고... 그외에도 문제가 많다. 가장 먼저 떠오르는 010은 10으로 봐야하나부터 시작해서 특수문자, 이모지 등등... 정말 많은 문제가 있다.

 

어떻게 할지 하나씩 정리해보자.

 

본 포스팅은 PostgreSQL을 기준으로 작성되었다. 

 

1. 유니코드 정렬과 언어 기준 정렬 설정

가장 먼저 알아야할게 PostgreSQL은 문자열을 정렬할 때 유니코드를 기준으로 정렬한다는 것이다.

 

유니코드란 전 세계의 모든 문자를 고유한 숫자 코드로 매핑한 표준 문자 인코딩 시스템인데, 각 문자를 고유한 코드 포인트(숫자 값)로 정의하여, 서로 다른 언어와 문자들을 동일한 방식으로 처리할 수 있게 해준다. 유니코드의 문자열 테이블은 여기서 확인할 수 있다. https://symbl.cc/en/unicode-table/

 

문제는 PostgreSQL에서 사용하는 유니코드 기본 정렬은 한글을 잘 정렬하지 못한다... 아래의 예시를 보면 

SELECT * FROM example ORDER BY name asc;

!!@#@! 
こんにちは 
🧡💛💚💙
정렬테스트중
00000012
020
11
19 한글 포함
A1
カタカナfile
hello
hey
漢字파일

이상하게 나온다. 그래서 COLLATE 옵션을 추가해줘야 한다. COLLATE문자열을 정렬할 때 사용하는 정렬 규칙을 정의하는 역할인데, 이 옵션을 사용하면 문자열을 해당 언어나 지역에 맞게 올바르게 정렬할 수 있다. 간단히 말해, COLLATE는 문자열 비교 시 어떤 언어의 정렬 규칙을 적용할지 결정하는 역할을 한다.

SELECT * FROM example ORDER BY name COLLATE "ko_KR.utf8" ASC;

🧡💛💚💙
!!@#@!
00000012
020
11
19 한글 포함
A1
A77
hello
hey
こんにちは
カタカナfile
정렬테스트중
漢字파일

COLLATE 적용 후 잘 정렬되는 것을 확인할 수 있다. 이렇게되면 기본 유니코드 정렬이 아니라 한글 기준으로 정렬정책이 설정된 것이다.

2. 그래서 숫자는 어떻게 해야하나?

구글 드라이브와 윈도우를 비교해가면서 어떻게할지 정책을 정했다. 그 결과 약간의 조건이 붙었다. "이름에 정의된 문자가 모두 숫자일 때"는 앞에 붙은 0은 모두 없다고 보고 정렬한다. 이 정책은 구글 드라이브와 윈도우가 동일하게 갖는 정책이다.

 

여기선 정규표현식이 들어와야한다. 정규표현식을 간단히 설명하자면, 숫자 앞에 0이 포함됐을 때 다 지워라는 의미다.

SELECT * FROM example 
ORDER BY
  CASE 
    WHEN name ~ '^[0-9]+' 
    THEN CAST(substring(name FROM '^[0]*([0-9]+)') AS INTEGER)
    ELSE NULL
  END ASC, name collate "ko_KR.utf8";
  
11
00000012
19 한글 포함
020
🧡💛💚💙
!!@#@!
A1
A77
hello
hey
こんにちは
カタカナfile
정렬테스트중
漢字파일

숫자는 이제 의도대로 정렬이 되었다. 그런데 중간에 이모지와 특수문자가 있는데 이건 너무 어색한 것 같다. 

 

3. 이모지와 특수문자

이 역시 구글 드라이브와 윈도우를 참고 했는데 둘 다 특수 문자가, 이모지가 가장 먼저오고 그 다음이 특수문자가 온다. 그런데 PostgreSQL의 정렬방식을 보면 한글 정렬 방식이 적용 된 후에는 모두 다 이모지가 먼저왔다.

 

기획자분이 위 정렬 상황을 보더니 정책적으로 별 문제가 없다고 생각하셨는지 그냥 컨펌이 났다. 그래서 이모지가 최상단에 위치하게뒀다. 이걸 쿼리로 처리하면 다음과 같다.

SELECT *
FROM example
ORDER BY 
  CASE 
    WHEN name ~ '^[^\w가-힣0-9]' THEN 0   -- 특수문자/이모지
    WHEN name ~ '^[0-9]+' THEN 1          -- 숫자
    ELSE 2                                -- 기타
  END ASC,
  CASE 
    WHEN name ~ '^[0-9]+' THEN CAST(substring(name FROM '^[0]*([0-9]+)') AS INTEGER)
    ELSE NULL
  END ASC,
  name COLLATE "ko_KR.utf8" ASC;
  
🧡💛💚💙
!!@#@!
11
00000012
19 한글 포함
020
A1
A77
hello
hey
こんにちは
カタカナfile
정렬테스트중
漢字파일

 

현재 상태에서 특수문자를 최상단으로 처리해주려면 할 수는 있을 것 같은데, 추가적인 많은 정규 표현식이 필요할 것 같다.

 

4. 추가 : PostgresSQL엔 어떤 언어팩이 있을까?

당연히 다양한 언어 팩이 있다. 본인에게 맞는 걸 선택해서, collate로 적용해 사용하면된다. 이 포스팅에서는 ko_kr.utf8을 사용했지만 postgresSQL에는 더 다양한 한글 언어팩도 준비되어 있다. 아래 SQL문을 실행시켜보면 된다.

SELECT * FROM pg_collation;
SELECT * FROM pg_collation WHERE collname LIKE 'ko_%' OR collname LIKE '%korean%';

 

마치며

사실 아직 끝난게 아니다. 여기선 한글 기준으로 정렬이 적용한 것이다.

 

이정도면 충분해서 이렇게 뒀지만 세부정책이 추가된다면 조금 더 골머리를 썩힐 것 같다.

(사용자의 언어에 따라 다른 정렬이 반영되어야할 수 있다.)

 

그래도 이번 정렬 정책은 양반이었다.

 

시즌 별로 나누거나 좋아요한걸 먼저 표기하거나 등등 세부적인 정렬이 많을 수 있는데 할 때마다 진짜 머리가 아프다...

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함