Oracle: неправильно работает ORDER BY

yolki

т.е. он работает, но результат противоречит здравому смыслу, вот фрагмент:

, avocat, Bordeaux
, lawyer, Kyiv
, lawyer, Ostrava
A
<пропущено>
A. et PORRAS
A. MARCHETTI, avocat &#224; l'Aquila
A. Me.
a non-governmental organisation
A. Q.C. and
a solicitor practising in Newcastle
A.A.
Aachen

Видно, что порядок НЕ ТОТ. Такое впечатление, что Оракл при сортировке игнорирует точки, не различает регистр и т.п.
Как сделать правильный порядок?
Он должен быть таким (фрагмент)

"Justice"
"Liberty"
"Liberty" Organisation
<пропущено>
A. MARCHETTI, avocat &#224; l'Aquila
A. Me.
A. Q.C. and
A. and CHRISTIE
A. and GONI
A. and LOIZIDES
A. and VAN EMPEL
A. et ANGELOPOULOS
A. et B. agissent pour C.
A. et CENGIZ
A. et CENSI
A. et PORRAS
A.-E.

0000

Вроде все он различает

select *
from (select 'a' as F
from DUAL
union
select 'A' as F
from DUAL
union
select '.A' as F
from DUAL
union
select 'A.' as F
from DUAL
union
select 'B' as F
from DUAL
union
select 'b' as F from DUAL)
order by F

Тока тебе похоже сортировка другая нужна.

ava3443

У меня нормальный порядок - вроде бы такой, как тебе надо. Что я делаю не так?
SQL> DESC TEST

TABLE TEST
Name Null? Type
----------------------------------------- -------- ----------------------------
S NOT NULL VARCHAR2(100)


SQL> SELECT S FROM TEST ORDER BY S;

S
--------------------------------------------------------------------------------
"Justice"
"Liberty"
"Liberty" Organisation
, avocat, Bordeaux
, lawyer, Kyiv
, lawyer, Ostrava
A
A. MARCHETTI, avocat &#224; l'Aquila
A. Me.
A. Q.C. and
A. and CHRISTIE
A. and GONI
A. and LOIZIDES
A. and VAN EMPEL
A. et ANGELOPOULOS
A. et B. agissent pour C.
A. et CENGIZ
A. et CENSI
A. et PORRAS
A.-E.
A.A.
Aachen
a non-governmental organisation
a solicitor practising in Newcastle

24 rows selected.

P.S. Oracle 9.2.0.5, везде UTF8

yolki

так в том-то и вопрос: почему разным клиентам он возвращает разные результаты?

ava3443

какое значение у NLS_LANG? да и вообще, покажи все NLS_*
какой тип у поля, по которому сортируешь?

yolki

а где это смотреть? в смысле NLS?
поле типа VARCHAR2(200)

ava3443

SHOW PARAMETER NLS;

yolki


NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_calendar string
nls_comp string
nls_currency string
nls_date_format string
nls_date_language string
nls_dual_currency string
nls_iso_currency string
nls_language string AMERICAN
nls_length_semantics string BYTE
nls_nchar_conv_excp string FALSE
nls_numeric_characters string

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_sort string
nls_territory string AMERICA
nls_time_format string
nls_timestamp_format string
nls_timestamp_tz_format string
nls_time_tz_format string
SQL> exit

mbolik1

А можешь показать результат такого селекта:
SELECT ASCIISTR(name) FROM table ORDER BY NLSSORT(name, 'NLS_SORT = BINARY');

yolki

Ага, так сортировка работает.
Фрагмент:

ASCIISTR(HDVD_REPR)
---------------------
A
A-F.
A-L.
A.
A. A.
A. E.
A. MARCHETTI, avocat &#224; l"Aquila
A. Me.
A. Q.C. and
A. and CHRISTIE
A. and GONI
A. and LOIZIDES
A. and VAN EMPEL
A. et ANGELOPOULOS
A. et B. agissent pour C.
A. et CENGIZ
A. et CENSI
A. et PORRAS
A.-E.
A.-F.
A.-M.
A.-V.
A.A.
A.B.
A.C.T.
A.D.
A.D. (sister)
A.D. ABRAHAMSON and Co.
A.E.
A.G.
A.H.
A.H.M.M.
A.J.
A.J.L.J.
A.J.W.
A.K.
A.L.
A.M.
A.P.
A.P.L.
A.R.W.
A.W.M.
AAE
AARONSON

тогда вопрос - как изменять такие настройки ГЛОБАЛЬНО? Кого пинать за неправильно настроенную локаль (я правильно понимаю?)
Настраивается ли это при инсталляции или нужно руками донастраивать?

mbolik1

Изменить походу никак. Есть параметр NLS_SORT, но в его описании сказано что он уровня сесси.
С локалью есть два подхода:
1. Честно настроить её на сервере, правда я не знаю что при этом станет с существующими данными.
2. Выставлять на клиенте туже локаль что и на сервере, тогда Oracle считает что всё у всех хорошо и больше ничего не проверят и ничего не пытается перекодировать.
А вообще по этому поводу стоит ботать Globalization Support Guide.

ava3443

Есть параметр NLS_LANG, но в его описании сказано что он уровня сесси.
Не только уровня сессии. Можно выставить в окружении клиента, и будет он во всех сессиях (пока не переопределишь через alter session...)
на винде - в реестре: HKLM\SOFTWARE\ORACLE\ALL_HOMES\IDn
на юниксах - установкой переменной окружения

mbolik1

Я извиняюсь, я имел в виду NLS_SORT. Уже исправил.

ava3443

nls_language string AMERICAN
Порядок сортировки по умолчанию определяется тем, какой у тебя NLS_LANGUAGE. Он у тебя AMERICAN. Судя по данным, которые ты показывал, они у тебя явно не на английском языке. Ну так выстави на клиенте правильный NLS_LANG, например: NLS_LANG=FRENCH_FRANCE.WE8MSWIN1252 или NLS_LANG=FRENCH_FRANCE.UTF8 (смотря какую кодировку ты используешь). Как следствие получишь правильный NLS_LANGUAGE=FRENCH и правильный порядок сортировки.
Если тебе сортировка в соответствии с алфавитом используемого языка не подходит, а нужна именно BINARY, то выстави переменную NLS_SORT=BINARY на клиенте или каждый раз делай ALTER SESSION SET NLS_SORT=BINARY; ну или повесь триггер на логон, который будет делать alter session, но это уже изврат
P.S. В какой у тебя кодировке база данных, кстати?
SELECT * FROM NLS_DATABASE_PARAMETERS WHERE parameter='NLS_CHARACTERSET';

yolki

Французские строки там - это так, досадное недоразумение.
На самом деле наполнение примерно такое: 60% на английском и 40% на французском.
Причём половина строк имеет перевод на русский язык в виде:

Иванов Петр Михайлович / Ivanoff Pyotr Mikhajlovich

Поскольку отображается всё равно в браузер (кодировка 1251 французские спецсимволы обходятся html-кодами. Пофиг, что они влияют на сортировку.
Где надо - я вставлял "1", "2" в начала строк, которые мне надо, чтобы выдавались в начале списка. А вот тут меня ожидал облом - она цифры в конец засунула. Вот и начал разбираться.

NLS_CHARACTERSET CL8MSWIN1251
NLS_LANGUAGE AMERICAN

mbolik1

А какие у тебя параметры клиента? (NLS_)

ava3443

кстати, а чего говорит
SELECT VALUE FROM NLS_SESSION_PARAMETERS WHERE PARAMETER='NLS_SORT';
BINARY?

mbolik1



...
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_sort string
...

Вряд ли. А по умолчанию идёт язык вытянутый из NLS_LANG

ava3443

Я просто залез в документацию и прочитал что show parameters показывает initialization parameters, т.е. параметры базы, а не текущей сессии. Параметры текущей сессии - в представлении NLS_SESSION_PARAMETERS.

ava3443

Вряд ли. А по умолчанию идёт язык вытянутый из NLS_LANG
кстати, для NLS_LANGUAGE=AMERICAN в NLS_SORT будет "BINARY"
Нет такого языка "AMERICAN". И "ENGLISH" тоже нет.
http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101...
Наверное, потому что они с BINARY совпадают, на крайняк - с UNICODE_BINARY.

mbolik1

Если я правильно понял таблицу приоритетов, то вытягиваться будет из локального NLS_LANG. Который обычно на Windows-клиентах проставлен честно.

ava3443

Судя по ответам автора темы, у него на клиенте стоит NLS_LANG=AMERICAN_AMERICA.CL8MSWIN1251, откуда получим NLS_SORT=BINARY (можно увидеть в NLS_SESSION_PARAMETERS)

mbolik1

Вряд ли, тогда бы не было фигни с сортировкой. Тем более как ты справедливо заметил это всё параметры базы:
SHOW PARAMETER NLS;

SELECT * FROM NLS_DATABASE_PARAMETERS WHERE parameter='NLS_CHARACTERSET';

И вообще пока автор темы не приведёт параметры сессии, это всё умозрительные заключения.

ava3443

SELECT * FROM NLS_DATABASE_PARAMETERS WHERE parameter='NLS_CHARACTERSET';
Я бы даже сказал, просто SELECT * FROM NLS_SESSION_PARAMETERS;
Попробовал у себя поменять NLS_LANG на клиенте с AMERICAN_AMERICA.UTF8 на FRENCH_FRANCE.UTF8 и обратно. Если ставлю AMERICAN, то получаю параметр сессии NLS_SORT=BINARY, если же FRENCH, то NLS_SORT=FRENCH (проверял переконнекчиваясь к базе и выполняя запрос SELECT * FROM NLS_ SESSION_PARAMETERS WHERE parameter='NLS_SORT'; )

yolki


SELECT * FROM NLS_SESSION_PARAMETERS;

NLS_LANGUAGE RUSSIAN
NLS_TERRITORY CIS
NLS_CURRENCY р.
NLS_ISO_CURRENCY CIS
NLS_NUMERIC_CHARACTERS ,
NLS_CALENDAR GREGORIAN
NLS_DATE_FORMAT DD-Mon-RRRR
NLS_DATE_LANGUAGE RUSSIAN
NLS_SORT RUSSIAN
NLS_TIME_FORMAT HH24:MI:SSXFF
NLS_TIMESTAMP_FORMAT DD.MM.RR HH24:MI:SSXFF
NLS_TIME_TZ_FORMAT HH24:MI:SSXFF TZR
NLS_TIMESTAMP_TZ_FORMAT DD.MM.RR HH24:MI:SSXFF TZR
NLS_DUAL_CURRENCY р.
NLS_COMP BINARY
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CONV_EXCP FALSE

Кое-что проясняется. В базе вообще были предусмотрены только русские строки. Но вот захотелось иметь ещё и английские с французскими.
Не надо менять кодировку на UTF и проч.
Национальные символы навроде ö нормально заменяются на html-тэги.

ava3443

Национальные символы навроде ö нормально заменяются на html-тэги.
в общем, определяйся, хочешь ты всё-таки иметь французский в базе (и UTF-8 или хочешь html-тэги

bastii

а что в Оракл нельзя задавать параметры кодировки и сортировки индивидуально на отдельное текстовое поле?

ava3443

Насколько я знаю, кодировка у базы одна. А откуда такой вопрос и как он связан со всем предыдущим обсуждением?

yolki

Я это говорил с самого начала. Мне НУЖНЫ html-тэги. Мне не нужна UTFx

yolki

Как выставить NLS_SORT в BINARY глобально для всех сессий?

ava3443

Прямой ответ на твой вопрос - вроде только повесить триггер на логон.
А если по уму, то это за система в которой ты не контролируешь окружение клиентов, напрямую подключающихся к базе?

pitrik2

а что в Оракл нельзя задавать параметры кодировки и сортировки индивидуально на отдельное текстовое поле?
а что, это можно делать в какойто другой СУБД?

yolki

Много гетерогенных клиентов (штук 7 на вскидку) - на трёх языках программирования написанных (Java, Delphi, C++). Каждый специально локаль не выставляет - используется "настройки по умолчанию". Вот и не хочется в коде каждого клиента копошиться, а сделать всё на сервере.
Это даже не столько клиенты, сколько около-"сервер приложений"

ava3443

ну так если это ограниченное число апп-серверов, выстави просто на каждом в окружении NLS_LANG и ничего не надо править в коде.

yolki

"окружение" = переменные среды?
ага, у простых клиентов, сработало.
Однако до jsp-сервлетов почему-то не дошло. перезапуск сервисов не помог. может, машину перегрузить?...

ava3443

если Windows, то в реестре

yolki

upd. ребут не помог.
хм. можно более конкретное место в реестре?

ava3443

HKLM\SOFTWARE\ORACLE\HOME0

yolki

так, в какое значение надо поставить NLS_LANG?
сейчас стоит AMERICAN_AMERICA.CL8MSWIN1251
ЗЫ. Добавление параметра NLS_SORT=BINARY (REG_SZ) не помогло

ava3443

сейчас стоит AMERICAN_AMERICA.CL8MSWIN1251
ты это проверил по NLS_SESSION_PARAMETERS?

yolki

нет, посмотрел в реестре
select * from NLS_SESSION_PARAMETERS выдаёт

NLS_LANGUAGE RUSSIAN

ava3443

Значит я тебе не то место в реестре указал. Поищи, где там ещё есть NLS_LANG, причём "RUSSIAN_CIS.CL8MSWIN1251"
Дока по теме:
Oracle9i Database Getting Started Release 2 (9.2) for Windows
9 Configuration Parameters and the Registry
Registry Parameters
(ссылка на онлайновую доку)

yolki

Так, рассмотрим дополнительно вариант тригера на логон.
Либо я чего-то недопонимаю в тригерах либо его нельзя создать в принципе.
Ну не даёт он мне ALTER SESSION SET NLS_SORT=BINARY в тело тригера ставить

ava3443

create or replace trigger after_logon
after logon on database
begin
execute immediate
'alter session set nls_sort = ''BINARY''';
end;
/

mbolik1

Я тебе советую не использовать тригер, лучше настрой локали.
Дело в том что при несовпадении локалей Oracle производит перекодирование и если какой-то символ вдруг оказывается непечатаемым, то он заменяется на знаки вопроса.

bastii

Насколько я знаю, кодировка у базы одна. А откуда такой вопрос и как он связан со всем предыдущим обсуждением?
Просто интересно — надо было оффтоп поставить. Полезный фокус может получиться: если, например, текстовое поле играет роль идентификатора, и используется только для организации связи, то можно было бы использовать бинарную сортировку, т.к. она быстрее, чем сортировка по словарю. В прочем, не знаю, насколько это интересно на практике, в теории кажется что полезнo.
P. S. В SQL Server управлять параметрами сортировки можно для отдельных текстовых полей.

ava3443

Полезный фокус может получиться: если, например, текстовое поле играет роль идентификатора, и используется только для организации связи, то можно было бы использовать бинарную сортировку, т.к. она быстрее, чем сортировка по словарю. В прочем, не знаю, насколько это интересно на практике, в теории кажется что полезнo.
На практике ни разу не видел текстовых полей, используемых для организации связи.
P. S. В SQL Server управлять параметрами сортировки можно для отдельных текстовых полей.
можно для отдельного поля задать порядок сортировки, который будет использоваться по умолчанию?

bastii

Поэтому индексы тоже будут правильными. А пример я просто так привел.
Как в Оракл реализовать словарь, когда нужно искать слово по одному языку и по другому языку. По идее нужно два индекса, в каждом сортировка определяется своим языком.

ava3443

Как в Оракл реализовать словарь, когда нужно искать слово по одному языку и по другому языку. По идее нужно два индекса, в каждом сортировка определяется своим языком.
CREATE INDEX french_index ON employees (NLSSORT(employee_id, 'NLS_SORT=FRENCH';
CREATE INDEX german_index ON employees (NLSSORT(employee_id, 'NLS_SORT=GERMAN';
P.S. ссылка на документацию:
Oracle9i Database Globalization Support Guide Release 2 (9.2)
4 Linguistic Sorting
Using Linguistic Indexes

bastii

да, не повезло юзерам и админам
как-то странно такое видеть в объектно-реляционной СУБД

ava3443

что не нравится?
и как это делается в SQL Server, с которым "повезло" юзерам и админам?

bastii

по идее указывается правильный collation для столбца при создании таблицы, дальше все делает SQL Server сам

ava3443

дальше все делает SQL Server сам
всё - это что?
как он поймёт, когда ты хочешь сортировку по-французски, а когда по-немецки, если (как ты написал) разработчик засунул и то, и другое в один столбец?

bastii

как он поймёт, когда ты хочешь сортировку по-французски, а когда по-немецки, если так сложилось, что разработчик засунул и то, и другое в один столбец?
ну, возможно, что это будет не лучшее решение разработчика смешивать два языка в одном столбце

mbolik1

А как ты вообще собирался засовывать в разные языки в одни столбец, если они не в одной кодировке(например utf32)?

ava3443

а почему не в одной? я имел ввиду два разных языка в одном столбце в одной кодировке (тот же UTF8)

mbolik1

А если в одной тогда нет проблем с сортировкой и поиском, единственный вопрос сначала будут отсортированные английские строки потом отсортированные французские или наоборот.
Оставить комментарий
Имя или ник:
Комментарий: