Опубликован: 28.12.2011 | Уровень: для всех | Доступ: свободно
Лекция 7:

Выборка данных. Фразы ORDER BY, GROUP BY и CONNECT BY предложения SELECT. Множественные операции

< Лекция 6 || Лекция 7: 123456 || Лекция 8 >
Аннотация: Применительно к предложению SELECT рассматриваются фразы ORDER BY для упорядочения строк окончательного ответа, GROUP BY для группировки строк по общим признакам и CONNECT BY для выполнения запросов по иерархически организованым данным.

Фраза ORDER BY предложения SELECT

Фраза ORDER BY дает единственно законный способ получить упорядоченный результат запроса на SQL, за исключением запросов с CONNECT BY.

Простейшая сортировка

SELECT ename, sal FROM emp ORDER BY sal;

Строки ответа сортируются по возрастанию величины зарплаты. Убывающий порядок должен задаваться явным способом с помощью слова DESC:

SELECT ename, hiredate FROM emp ORDER BY hiredate DESC;

В противовес этому ради ясности можно сослаться на возрастающий порядок с помощью формально необязательного слова ASC.

Упорядочение строк ответа по нескольким столбцам задается перечислением в ORDER BY столбцов через запятую.

Пусть имеется предложение

SELECT ename, sal FROM emp;

Допустимые варианты формулировок фразы ORDER BY:

ORDER BY ename DESC
ORDER BY sal ASC, ename DESC
ORDER BY sal, ename
ORDER BY emp.sal
ORDER BY emp.ename DESC, sal, hiredate DESC

Упорядочение по значению выражения

SELECT ename FROM emp ORDER BY NVL ( sal, 0 ) + NVL ( comm, 0 );
SELECT ename, hiredate FROM emp ORDER BY TRUNC ( hiredate ) DESC;

Если проставить в качестве значения упорядочения функцию выдачи случайных чисел, фразой ORDER BY можно добиться (псевдо)случайного порядка строк в результате:

SELECT ename FROM emp ORDER BY DBMS_RANDOM.VALUE;

Указание номера столбца

Если в выражении для упорядочения указано явное целое число, то оно воспринимается не как признак упорядочения, а как номер столбца во фразе SELECT, по значениям которого следует упорядочить результат:

SELECT job, AVG ( sal ) FROM emp 
GROUP  BY job
ORDER  BY 2;

Указание номера во фразе ORDER BY может сделать формулировку запроса более надежной, если результат следует упорядочить по столбцу, построенному на основе "полноценного" выражения. Менее надежная, но идентичная по результату формулировка запроса выше:

SELECT job, AVG ( sal ) FROM emp 
GROUP  BY job
ORDER  BY AVG ( sal );

Ее недостаток: повторяя (или исправляя) выражение, программист может ошибиться и в том, что для сложных выражений СУБД может не распознать их идентичность и вычислять дважды (в простых случаях оптимизатор запросов в Oracle двукратного вычисления делать не будет).

Третий, равносильный по результату вариант формулировки запроса сохраняет преимущество первой формулировки перед второй, но лишен ее недостатка:

SELECT job, AVG ( sal ) avgsal FROM emp 
GROUP  BY job
ORDER  BY avgsal;

Она позволяет СУБД единожды, а не дважды вычислить выражение, устраняет риск ошибки программиста при повторении записи выражения и не опирается на номер столбца. Ее-то и можно рекомендовать для использования в приложении. Интересно, что в ней SQL дает очередной пример собственной непоследовательности: нарушает свою же логическую схему обработки запроса, позволив сослаться в предпоследней по порядку выполнения фразе ORDER BY на название AVGSAL, определенное позже, в завершающей фразе SELECT.

Упорядочение текстовых значений: двоичное и по правилам языка

В отличие от данных других видов, в основе упорядочения строк текста имеется два содержательно разных способа их сравнения: по двоичным кодам отдельных символов и по правилам языка. Требуемый способ определяется параметром СУБД NLS_SORT, допускающим установку индивидуально для сеансов. Проверка:

INSERT INTO emp ( empno, ename ) VALUES ( 1111, 'adams' );
ALTER SESSION SET NLS_SORT = BINARY;
SELECT ename FROM emp ORDER BY ename;
Результат:
ENAME
----------
ADAMS
ALLEN
BLAKE
...
WARD
adams

Результат приведен для русских кодировок для Unix/Windows, построенных на основе ASCII. В случае кодировки на основе EBCDIC порядок результата будет фиксированный, но иной. Сравнение текстов на основе кодов символов — наиболее быстрое.

Далее:

ALTER SESSION SET NLS_SORT = RUSSIAN;
SELECT ename FROM emp ORDER BY ename;
Результат:
ENAME
----------
ADAMS
adams
ALLEN
BLAKE
...
WARD

Этот результат соответствует традиционному для русского языка порядку строк, знакомому по словарям докомпьютерных времен. Он достигается определенными дополнительными затратами на обработку. На латинских буквах, как в этом примере, с равным успехом можно было применить NLS_SORT= LATIN.

Далее:

ALTER SESSION SET NLS_SORT = RUSSIAN_CI;
SELECT ename FROM emp ORDER BY ename;
Результат:
ENAME
----------
adams
ADAMS
ALLEN
BLAKE
...
WARD

Указание CI в значении для NLS_LANG расшифровывается как case-insensitive, то есть игнорирование регистра. Отсюда иное расположение "маленького Адамса" в результате, которое, впрочем, не гарантировано (регистр не принимается во внимание!) Для чисто латинских букв соответствующее значение записывается как LATIN_CI.

Восстановим данные:

ROLLBACK;

Специальная функция NLSSORT позволяет указать нужный способ сортировки независимо от установок сеанса:

SELECT ename FROM emp ORDER BY NLSSORT ( ename, 'NLS_SORT=RUSSIAN' );

Эту функцию можно использовать в любых выражениях, где играет роль порядок присутствующих значений, например:

SELECT ename 
FROM   emp 
WHERE
         NLSSORT ( ename,   'NLS_SORT=RUSSIAN' )
 BETWEEN NLSSORT ( 'allen', 'NLS_SORT=RUSSIAN' )
     AND NLSSORT ( 'KING',  'NLS_SORT=RUSSIAN' ) 
;

Пример с русскими буквами имеет дополнительную окраску в силу особого расположения в кодировочной таблице буквы "ё":

SQL> ALTER SESSION SET NLS_SORT = BINARY;
SQL> SELECT DECODE ( ROWNUM, 1, 'е', 2, 'ё', 3, 'Ж', 4, 'Ё' ) ltr
  2  FROM dept ORDER BY ltr;
L
-
Ё
ё
Ж
е
SQL> ALTER SESSION SET NLS_SORT = RUSSIAN;
Session altered.
SQL> SELECT DECODE ( ROWNUM, 1, 'е', 2, 'ё', 3, 'Ж', 4, 'Ё' ) ltr
  2  FROM dept ORDER BY ltr;
L
-
е
Ё
ё
Ж
SQL> SELECT DECODE ( ROWNUM, 1, 'е', 2, 'ё', 3, 'Ж', 4, 'Ё' ) ltr
  2  FROM dept ORDER BY NLSSORT ( ltr, 'NLS_SORT=BINARY' );
L
-
Ё
ё
Ж
е

(Примеры с русскими буквами отработают правильно, если перед вызовом клиентской программы, а в данном случае это SQL*Plus, установить корректное значение переменной среды окружения ОС NLS_LANG).

В условных выражениях (фраза WHERE в SQL или в блоках PL/SQL) принимается во внимание не только значение параметра NLS_SORT, но и NLS_COMP. Последнее может быть BINARY или LINGUISTIC. Если NLS_COMP = LINGUISTIC, решение принимается исходя из значения NLS_SORT. Пример разъясняющей последовательности действий:

ALTER SESSION SET NLS_COMP = BINARY;
ALTER SESSION SET NLS_SORT = BINARY;
SELECT 'е < ё' FROM dual WHERE 'е' < 'ё';
ALTER SESSION SET NLS_COMP = BINARY;
ALTER SESSION SET NLS_SORT = RUSSIAN;
SELECT 'е < ё' FROM dual WHERE 'е' < 'ё';
ALTER SESSION SET NLS_COMP = LINGUISTIC;
ALTER SESSION SET NLS_SORT = BINARY;
SELECT 'е < ё' FROM dual WHERE 'е' < 'ё';
ALTER SESSION SET NLS_COMP = LINGUISTIC;
ALTER SESSION SET NLS_SORT = RUSSIAN;
SELECT 'е < ё' FROM dual WHERE 'е' < 'ё';

Упражнение. Выполните приведенные выше операции и пронаблюдатйте эффект различных комбинаций значений на сравнение величин.

Другие особенности параметров СУБД (сеанса), определяющих различные модели сравнения текстов, приведены в документации по Oracle.

Текущие значения параметров сравнения и сортировки своего сеанса можно посмотреть в таблице словаря-справочника NLS_SESSION_PARAMETERS, выдав:

SELECT * 
FROM 
  nls_session_parameters 
WHERE
  parameter IN ( 'NLS_COMP', 'NLS_SORT' )
;

Особенности обработки отсутствующих значений при сортировке

Если не указать особо, отсутствующие значения интерпретируются в Oracle как наибольшие для соответствующего типа. При сортировке по возрастанию они размещаются в конце, а по убыванию — в начале списка (в стандарте SQL это не зафиксировано). Влиять на расположение строк с отсутствующими значениями полей можно во фразе ORDER BY с помощью указаний NULLS FIRST и NULLS LAST.

Пример:

SELECT   ename, comm
FROM     emp
ORDER BY comm 
   NULLS FIRST
;
< Лекция 6 || Лекция 7: 123456 || Лекция 8 >
Ярослав Прозоров
Ярослав Прозоров

В лекции № 7 "Введение в Oracle SQL" в подразделе "Несамостоятельность группировки с обобщениями ROLLUP, CUBE и GROUPING SETS"  представленная таблица сравнения содержит ошибки - окончания запросов пропущены. Видимо, ошибки вызваны некорректным переносом материала лекции.

Володимир Миколайчук
Володимир Миколайчук
Помогите разобраться поетапно с логикой запроса
-------TOOLS
NAME PRICE TYPE
drill 155 A
sawzall 192 N
mitre saw 292 M
router 86 I
RAD 145 M
jigsaw 128 I
screwdriver 77 P
------TOOL_TYPES
TYPE USAGE
A Always
I Often
M Sometimes
N Rarely
P Never

Запрос SQL:
SELECT t.type, SUM(t.price)
FROM tools t
GROUP BY t.type
HAVING SUM(t.price) >= (SELECT AVG(price)
FROM tools
WHERE type IN (SELECT type
FROM tool_types
WHERE usage = 'Often'));

И сколько строк он все таки вернет
Жанбек Сарсенов
Жанбек Сарсенов
Россия, Москва, Московский Государственный Университет имени Ломоносова М.В., 2002