Sobre o ambiente:
Red Hat Enterprise Linux Server release 6.4 (Santiago)
PostgreSQL 9.2.4
LANG=pt_BR.UTF-8
Banco de dados
teste
, utilizando o encodingUTF-8
e oLC_TYPES
eCOLLATE
comopt_BR.UTF-8
`
Para exemplificar melhor o problema de ordenação, criei a tabela abaixo:
teste=# create table foo (id serial primary key, nome text);
NOTICE: CREATE TABLE will create implicit sequence "foo_id_seq" for serial column "foo.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
CREATE TABLE
teste=# \d foo
Tabela "public.foo"
Coluna | Tipo | Modificadores
--------+---------+----------------------------------------------------------
id | integer | não nulo valor padrão de nextval('foo_id_seq'::regclass)
nome | text |
Índices:
"foo_pkey" PRIMARY KEY, btree (id)
E inseri uns dados de teste:
teste=# insert into foo (nome) values ('CRIANSCA'), ('CRIANSCA'), ('CRIANÇA'), ('DANIEL ALDROVANO'), ('DANIELA LAZARUS'), ('DANIELA LEITE');
INSERT 0 6
Ao listar os dados, a primeira surpresa:
teste=# select * from foo order by nome ;
id | nome
----+--------------------------------
2 | CRIANCA
3 | CRIANÇA
1 | CRIANSCA
5 | DANIELA LAZARUS
4 | DANIEL ALDROVANO
6 | DANIELA LEITE
(6 registros)
Notem que o problema em sí está na ordem dada aos IDs 5, 4 e 6. Esse problema é esperado, devido ao fato que (nesse collate especificamente) a operação de ordenação é realizada sem os espaços, assim, DANIELALAZARUS
vem antes de DANIELALDROVANO
e assim por diante.
Para sanar o problema, pensei em mudar o collate para C por que o mesmo não ignora os espaços na operação de ordenação, porém surgiu um novo problema: os acentos não são ordenados corretamente.
teste=# create collation teste (locale='C');
CREATE COLLATION
teste=# select * from foo order by nome collate teste;
id | nome
----+--------------------------------
2 | CRIANCA
1 | CRIANSCA
3 | CRIANÇA
4 | DANIEL ALDROVANO
5 | DANIELA LAZARUS
6 | DANIELA LEITE
(6 registros)
Para sanar o problema, edite o arquivo /usr/share/i18n/locales/pt_BR
, e adicione antes de END LC_COLLATE
:
reorder-after <U00A0>
<U0020><CAP>;<CAP>;<CAP>;<U0020>
reorder-end
Aplique as modificações, rodando o comando abaixo:
localedef -i pt_BR -c -f UTF-8 -A /usr/share/locale/locale.alias pt_BR
Após configurar o locale, reinicie o banco de dados.
Assim os dados são ordenados corretamente:
teste=# select * from foo order by nome;
id | nome
----+--------------------------------
2 | CRIANCA
3 | CRIANÇA
1 | CRIANSCA
4 | DANIEL ALDROVANO
5 | DANIELA LAZARUS
6 | DANIELA LEITE
(6 registros)
Em especial, um obrigado ao @fabriziomello pela dica.