• Строчные функции и преобразование типов — Итоги

    Описание функций в SQL

    • Функции могут принимать ноль или более параметров, но всегда возвращают только один элемент предопределённого типа данных
    • Строчные функции выполняются для каждой выбираемой строки, функции группировки выполняются один раз для всего набора данных.
    • Функции для работы со строками включают в себя функции для работы с регистром и функции для обработки значений

     

    Использование функций обработки строк, чисел и данных в команде SELECT

    • Функция INITCAP принимает исходную строку и возвращает результат в котором каждое слово начинается с заглавной буквы
    • Функция для получения длины строки, включая пробелы и специальные символы – это фунция LENGTH
    • Функция INSTR возвращает позицию n-ого вхождения заданной подстроки в строке
    • Функция SUBSTR возвращает подстроку по заданной позиции из исходной строки
    • Функция REPLACE заменяет все вхождения искомого элемента в исхожной строке и возвращает новое значение
    • Функция MOD выполняет операцию деления с остатком и возвращает остаток от деления
    • Численная функция ROUND округляет заданное значение вверх или вниз с указанной точностью
    • Функция SYSDATE часто используется при запросах в таблицу DUAL для получения текущего системного времени и даты
    • Разница между двумя датам это всегда число, которое представляет из себя количество дрей между двумя датами
    • Функция MONTHS_BETWEEN вычисляет количество месяцев между двумя датами, и она основана на допущении что в неопределённом месяце 31 день
    • Функция LAST_DAY вычисляет последний день месяца получаемого из заданной даты

     

    Описание функций конвертации

    • Явная конвертация происходит при вызове функций типа TO_CHAR для изменения типа данных. Функция TO_CHAR преобразует дату и число в строку
    • Строки явно преобразуются в дату используя функцию конвертации TO_DATE
    • Строки явно преобразуются в число используя функцию TO_NUMBER

     

    Использование функций TO_CHAR, TO_NUMBER и TO_DATE

    • Функция TO_CHAR возвращает значение типа VARCHAR2
    • Маска (или модель) форматирования устанавливает шаблон которой строка должна удовлетворять для корректного и целостного корвентирования значения в элемент типа ДАТА
    • Элементы строки, такие как месяц или день полученные из даты с помощью функции TO_CHAR автоматически обрамляются пробелом, но такое поведение можно отменить используя параметр fm
    • В функции TO_DATE можно использовать параметр fx который требует точного совпадения формата значения заданной маске

     

    Использование выражений ветвления в команде SELECT

    • Вложенные функции используют результат вычисления одной функции как входной параметр для другой
    • Функция NVL возвращает либо исходное значение, либо альтернативное значение если исходный элемент равен NULL
    • Функция NVL2 возвращает новый элемент if-null если исходное значение проверяемного параметра равно NULL инче возвращает альтернативное значение if-not-null
    • Функция NULLIF проверяет два элемента на идентичность. Если они одинаковы, то функция возвращает NULL иначе первый из сравниваемых элементов
    • Фунция COALESCE возвращает первое не-NULL значение из списка параметров. Если все параметры NULL, то возвращается NULL
    • Функция DECODE и выражение CASE используются для реализации IF-THEN-ELSE логики.
  • Операторы ветвления в команде SELECT

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

     

    Вложенные функции

     

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

     

    Function1(parameter1, parameter2, …) = result

     

    Замена параметра функции на вызов другой функции может привести к появлению выражений вида

     

    F1( param1.1, F2( param2.1, param2.2, F3( param3.1)), param1.3)

     

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

    1. Вычисляется функция F3(param1) и возвращаемое значение используется как третий параметр для функции 2, назовём его param2.3
    2. Затем вычисляется функция F2(param1, param2.2, param2.3) и возвращаемое значение используется как второй параметр функции F1 – param1.2
    3. И наконец вычисляется функция F1(param1, param2, param1.3) и результат возвращается в вызывающую программу.

    Таким образом функция F3 находится на третьем уровне вложенности.

    Рассмотрим запрос

     

    select next_day(last_day(sysdate)-7, ‘tue’) from dual;

     

    1. В этом запросе три функции, от нижнего уровня к верхнему – SYSDATE, LAST_DAY, NEXT_DAY. Запрос выполняется следующим образом
    2. Выполняется самая вложенная функция SYSDATE. Она возвращает текущее системное время. Предположим, что текущая дата 28 октября 2009 года
    3. Далее вычисляется результат функция второго уровня LAST_DAY. LAST_DATE(’28-OCT-2009’) возвращает последний день окбября 2009 года, то есть значение 31 октябрая 2009.
    4. Затем происходит вычитания из этой даты семи дней – получается 24 октября.
    5. И наконец вычисляется функция NEXT_DAY(’24-OCT-2009’, ‘tue’), и запрос возвращает последний вторник октября – что в нашем примере 27-OCT-2009.

     

    Tip

    Достаточно сложно разбираться и строить сложные выражения используя много вложенных вызовов функций, но это приходит со временем и практикой. Можно разбивать такие выражения на части и тестировать отдельно. Таблица DUAL очень полезно для тестирования з.апросов и результатов вызова функций. Можно тестировать и отлаживать небольшие компоненты, которые затем совмещать в одно большое нужное выражение.

     

    Функции ветвления

     

    Функции ветвления, также известные как ЕСЛИ-ТО-ИНАЧЕ, используется для определения пути выполнения в зависимости от каких-либо обстоятельств. Функции ветвления возвращают разные результат основываясь не результате вычисления условия. В группе таких функций выделяют функции работы со значением NULL: NVL, NVL2, NULLIF и COALESCE. И также общие функции, представленные функцией DECODE и выражением CASE. Функция DECODE является Oracle функцией, тогда как CASE выражение присутствует в стандарте ANSI SQL.

     

    Функция NVL

     

    Функция NVL проверяет значение столбца или выражения любого типа данных на значение NULL. Если значение NULL – она возвращает альтернативное не-NULL значение по умолчанию, иначе возвращается исходное значение.

    У функции NVL два обязательных параметра и синтаксис NVL(original, ifnull) где original это исходное значение для проверки и ifnull результат возвращаемый функцией если original значение равно NULL. Тип данных параметров ifnull и original должен быть совместим. То есть либо тип данных должен быть одинаковым или должна быть возможность неявной конвертации значений из одного типа в другой. Функция NVL возвращает значение такого же типа данных как тип данных параметра original. Рассмотрим три запроса

     

    Query 1: select nvl(1234) from dual;

    Query 2: select nvl(null, 1234) from dual;

    Query 3: select nvl(substr(‘abc’, 4), ‘No substring exists’) from dual;

     

    Так как функции NVL необходимо два параметра, запрос 1 вернёт ошибку ORA-00909: invalid number of arguments. Запрос 2 вернёт 1234 так как проверяется значение NULL и оно равно NULL. Запрос три используется вложенную SUBSTR функцию которая пытается выделить четвёртый символ из строки длиной в три символа, возвращает значение NULL, а функция NVL возвращает строку ‘No sbustring exists’.

     

    Tip

    Функция NVL очень полезна при работе с числами. Она используется для конвертации NULL значений в 0, чтобы арифметические операции над числами не возвращали NULL

     

    Функция NVL2

     

    Функция NVL2 предоставляет больше функционала чем NVL, но служит также для обработки значения NULL. Она проверяет значение столбца или выражения любого типа на значение NULL. Если значение не равно NULL, то вовзращается второй параметр, иначе возвращается третий параметр, в отличии от функции NVL, которая в этом случае возвращает исходное значение.

    У функции NVL2 три обязательных параметра и синтаксис NVL2(original, ifnotnull, ifnull), где original – это проверяемое значение, ifnotnull значение возвращаемое в случае если original не равно NULL и ifnull значение возвращаемое в случаем если original равно NULL. Типы данных параметров ifnotnull и ifnull должы быть совместимы, и они не могут быть типа LONG. Тип данных возвращаемых функцией NVL2 равен типу данных параметра ifnotnull. Рассмотрим несколько примеров

     

    Query 1: select nvl2(1234, 1, ‘a string’) from dual;

    Query 2: select nvl2(null, 1234, 5678) from dual;

    Query 3: select nvl2(substr(‘abc’, 2), ‘Not bc’, ‘No substring’) from dual;

     

    Параметра ifnotnull в запросе 1 это число, а параметр ifnull – это строка. Так как типы данных несовместимы, возвращается ошибка “ORA-01722: invalid number”. Запрос два возвращает ifnull параметр, так как original равно NULL и результатом будет 5678. Запрос три использует функция SUBSTR которая возвращает ‘bc’ и происходит вызов NVL2(‘bc’,’Not bc’,’No substring’) – который возвращает ifnotnull параметр – ‘Not bc’.

     

    Функция NULLIF

     

    Функция NULLIF проверяет два значения на идентичность. Если они одинаковы – возвращается NULL иначе возвращается первый параметр. У функции NULLIF два обязательных параметра и синтаксис NULLIF(ifunequal, comparison_item). Функция сравнивает два параметра и если они идентичны – возвращается NULL, иначе параметр ifunequal. Рассмотрим запросы

     

    Query 1: select nullif(1234, 1234) from dual;

    Query 2: select nullif(’24-JUL-2009′, ’24-JUL-09′) from dual;

     

    Запрос один возвращает NULL так как параметры идентичны. Строки в запросе 2 не конвертируются в дату, а сравниваются как строки. Так как строки разной длины – возвращается параметра ifunequal 24-JUL-2009.

    На рисунке 10-4 функция NULLIF вложена в функцию NVL2. В функции NULLIF в свою очередь используются функции SUBSTR и UPPER как части выражения в параметре ifunequal. Столбец EMAIL сравнивается с этим выражением, возвращающем первую букву имени, объединённую с фамилией для сотрудников у которых имя длиной в 4 символа. Когда эти значения равны, NULLIF вернёт NULL, иначение вернёт значение параметра ifunequal. Эти значения используюся как параметр для функции NVL2. NVL2 в свою очередь возвращает описание совпадали ли сравниваемые элементы или нет.

    1

    Рисунок 10-4 – Использование функции NULLIF

     

    Функция COALESCE

     

    Функция COALESCE возвращает первое значение не равное NULL из списка параметров. Если все параметры равны NULL, то возвращается NULL. У функции COALESCE два обязательных параметра и сколько угодно необязательных параметров и синтаксис COALESCE(expr1, expr2, …, exprn) где результатом будет expr1 если значение expr 1не NULL, иначе результатом будет expr2 если оно не NULL и т.д. COALESCE равно по смыслу вложенным функциям NVL

     

    COALESCE(expr1, expr2) = NVL (expr1, expr2)

    COALESCE(expr1, expr2, expr3) = NVL(expr1,NVL(expr2, expr3))

     

    Тип данных возвращаемого значение если найдено не NULL значение равен типу данных первого не NULL значения. Для того чтобы избежать ошибки ‘ORA-00932: inconsistent data types’ все не NULL параметры должны быть совместимы с первым не NULL параметром. Рассмотрим три примера

     

    Query 1: select coalesce(null, null, null, ‘a string’) from dual;

    Query 2: select coalesce(null, null, null) from dual;

    Query 3: select coalesce(substr(‘abc’, 4), ‘Not bc’, ‘No substring’) from dual;

     

    Запрос 1 возвращает четвёртый параметр: строку, так как это первый не NULL параметр. Запрос два возвращает NULL так как все параметры равны NULL. Запрос 3 вычисляет первый параметр, получает значение NULL и возвращает второй параметр, так как он первый не NULL параметр.

     

    Exam tip

    Параметры функции NVL2 могут запутать если вы уже знакомы с функцие NVL. NVL(original, ifnull) возвращает original если значение не NULL, иначе ifnull. NVL2(original, ifnotnull, ifnull) возвращает ifnotnull если значение original не равно NULL иначе ifnull. Путаница происходит из-за того, что второй параметра функции NVL ifnull, тогда как у NVL2 это ifnotnull. Так что не надейтесь на позицию параметра в функции.

     

    Функция DECODE

     

    Функция DECODE реализует if-then-else логику проверяя первые два параметра на равенство и возвращая третье значение в случае их равенства или другое значение в случае неравенства. У функции DECODE три обязательных параметра и синтаксис DECODE(expr1, comp1, iftrue1, [comp2, iftrue2 … [compN, iftrueN], [iffalse]). Эти параметры используются как показано в слеующем примере псевдокода

     

    IF expr1=comp1 then return iftrue1

    Else if expr1=comp2 then return iftrue2

    Else if exprN=compN then return iftrueN

    Else return NULL|iffalse;

     

    Вначале expr1 сравнивается с comp1. Если они равны возвращается значение iftrue1. Если expr1 не равно comp1, то что происходит дальше зависит от того заданы ли параметры comp2 и iftrue2. Если заданы, тов значение expr1 сравнивается с comp2. Если значения равны, то возвращается iftrue2. Если нет, то если есть пары параметров compN, iftrueN происходит сравнение expr1 и compN и в случае равнества возвращается iftrueN. Если не было найдено совпадение ни в одном наборе параметров, то возвращается или iffalse если этот параметр был задан, или NULL.

    Все параметры в функции DECODE могут быть выражениями. Тип возвращаемого значения равен типу первого проверяющего элемента – параметра comp1. Выражение expr1 неявно преобразуется к типу данных параметра comp1. Все остальные доступные параметры comp1 … compN также неявно преобразуются к типу comp1. DECODE рассматривает значение NULL как равное другому значению NULL, т.е. если expr1 is NULL и comp3 is NULL, а comp2 не NULL, то возвращается значение iftrue3. Рассмотрим несколько примеров

     

    Query 1: select decode(1234, 123, ‘123 is a match’) from dual;

    Query 2: select decode(1234, 123, ‘123 is a match’, ‘No match’) from dual;

    Query 3: select decode(‘search’, ‘comp1’, ‘true1’, ‘comp2’, ‘true2’, ‘search’, ‘true3’, substr(‘2search’, 2, 6), ‘true4’, ‘false’) from dual;

     

    Запрос один сравнивает значение 1234 и 123. Так как они не равны то iftrue1 игнорируется и так как не определено значение iffalse то возвращается NULL. Запрос два идентичен запросу 1 за тем исключением что значение iffalse определено. Так как 1234 не равно 123 то возвращается iffalse – ‘No match’. Запрос три проверяет значения параметров на совпадения значению search. Параметры comp1 и comp2 не равны ‘search’ поэтому результаты iftrue1 и iftrue2 пропускаются. Совпадение найдено в третьей операции сравнения элемента comp3 (позиция параметра 6) и возвращается значение iftrue3 (параметр 7) которое равно ‘true3’. Так как совпадение найдено больше вычисления не производятся. То есть несмотря на то что значение comp4 (параметр 8) также совпадает с expr1 – это выражение никогда не рассчитывается так как совпадение было найдено в предыдущем сравнении.

     

    Выражение CASE

     

    Все языки программирования третьего и четвертого поколения реализуют конструкцию case. Как и функция DECODE, выражение CASE позволяет реализовывать if-then-else логику. Доступны два варианта использования выражения CASE. Простое CASE выражение устанавливает исходный элемент для сравнения единожды, а затем перечисляет все необходимые условия проверки. Сложный (searched) CASE вычисляет оба оператора для каждого условия.

    У выражения CASE три обязательных параметра. Синтаксис выражения зависит от типа. Для простого CASE выражения он выглядит так

     

    CASE search_expr

    WHEN comparison_expr1 THEN iftrue1

    [WHEN comparison _expr2 THEN iftrue2

    WHEN comparison _exprN Then iftrueN

    ELSE iffalse]

    END

     

    Выражение заключается в CASE … END блок и должно иметь хотя бы один WHEN … THEN элемент. В своей простейшей форме с одинм WHEN … THEN элементом параметр search_expr сравнивается с comparison_expr1 и, если они равны, возвращается iftrue1. Если нет, то возвращается значение NULL если не указан элемент ELSE. Если ELSE присутствует в выражении, то возвращается значение iffalse. Если в выражении больше чем один WHEN … THEN, то происходит сравнение значения search_expr пока не будет найдено совпадение.

    Параметрами search_expr, comparison и iftrue могут быть значения столбца, выражения или литералы, но тип данных должен быть одинаковым. Рассмотрим следующий запрос

     

    select

    case substr(1234, 1, 3)

    when ‘134’ then

    ‘1234 is a match’

    when ‘1235’ then

    ‘1235 is a match’

    when concat(‘1′, ’23’) then

    concat(‘1′, ’23’)||’ is a match’

    else

    ‘no match’

    end

    from dual;

     

    Параметр search_expression рассчитываеся в функции SUBSTR и получается значение ‘123’. Первый WHEN … THEN сравнивает 134 и 123. Так как они не равны, проверяется следующий WHEN…THEN и сравнивается 123 с 12345 и значения снова не одинаковы. Третий WHEN … THEN сравнивает значение ‘123’ с выражением CONCAT(‘1’,’23’), которое даёт результат ‘123’. Сравниваемые значения равны, и возвращается результат третьего выражения ‘123 is a match’.

    На рисунке 10-5 выполняется запрос, который выбирает столбцы LAST_NAME и HIRE_DATE из таблицы EMPLOYEES где значение DEPARTMENT_ID равны 10 или 60, а также два выражения и выражение CASE.

    2

    Рисунок 10-5 – сложное CASE выражение

     

    Преположим что текущая дата 22 апреля 2016 года. Выражение с псевдонимом YEARS возвращает округленное в нижнюю сторону значения равного количеству месяцев с момента приёма на работу до текущей даты, разделённое на 12. Пять категорий лоялности сотрудника определены в зависимости от значения количества месяцев, проработанных в компании, делённых на число 60. Это значение формирует параметр condition1 для выражения CASE. Ни одна из строкв таблице не удовлетворяет первому условию, но удовлетворяет некоторым другим. Такие выражения называются сложными (searched) и синтаксис такого выражения

     

    CASE

    WHEN condition1 THEN iftrue1

    [WHEN condition2 THEN iftrue2

    WHEN conditionN THEN iftrueN

    ELSE iffalse]

    END

     

    Сложное выражение заключается в конструкцию CASE … END и состоит минимум из одного WHEN…THEN блока. В простейшей форме с одним блоком WHEN…THEN вычисляется condition1 и если значение возвращает логическое ДА, то возвращается iftrue, иначе возвращается NULL если не указан ELSE iffalse, при наличии которого вместо NULL возвращается iffalse. Если в CASE выражении больше чем один блок WHEN…THEN то вычисление происходит пока не будет найдено совпадение. Запрос для получения результата, похожего на представленный на рисунке 10-5

     

    select last_name, hire_date,

    trunc(months_between(sysdate, hire_date)/12) years,

    trunc(months_between(sysdate, hire_date)/60) «Years divided by 5»,

    case

    when trunc(months_between(sysdate, hire_date)/60) < 1 then ‘Intern’

    when trunc(months_between(sysdate, hire_date)/60) < 2 then ‘Junior’

    when trunc(months_between(sysdate, hire_date)/60) < 3 then ‘Intermediate’

    when trunc(months_between(sysdate, hire_date)/60) < 4 then ‘Senior’

    else

    ‘Furniture’

    end Loyalty

    from employees

    where department_id in (60,10);

     

    Чтобы убедиться что CASE вычисляет значения только до первого совпадения можно выполнить запрос

     

    select case ‘A’

    when ‘A’ then

    ‘X’

    when ‘A’ then

    ‘X1’

    else

    ‘X3’

    end as f1

    from dual;

  • Функции конвертации типов данных доступные в SQL

    Строчные функции конвертации типа данных разработаны для изменения типа данных столбца, выражения или литерала. Наиболее часто используемые функции конвертации это TO_CHAR, TO_NUMBER и TO_DATE. TO_CHAR преобразует числа и даты в символьные данные, когда TO_NUMBER и TO_DATE преобразует символьные данные соответственно в число и дату.

     

    Функции конвертации

     

    Oracle позволяет определять столбцы с типами данных ANSI, DB2 и SQL/DS. Эти типы преобразуется к типам данных Oracle. У каждого столбца определяется тип данных который ограничивает природу данных которые могут храниться в этом столбце. Столбец NUMBER не может хранить символьную информацию. Столбец DATE не может хранить случайные символы или числа. VARCHAR2 может хранить символьные эквиваленты чисел и дат.

    Если функция у которой входной параметр является строкой получает на вход число, Oracle автоматически конвертирует его в символьный эквивалент. Если функция с входными параметрами типа данных число или дата получает на вход строку, то должны соблюдаться определённые условия для автоматической конвертации. Несмотря на то что автоматическая неявная конвертация доступна, гораздо более понятно и надёжно явно сконвертировать один тип данных в другой перед вызовом строчной функции.

     

    Неявная конвертация типов

     

    Значения, которые не соответствуют типам данных параметров функции неявно конвертируется перед выполнением если это возможно. Оба типа данных VARCHAR2 и CHAR используются как символьные типы данных. Символьные типы данных достаточно гибкие для хранения практически любой информации. Таким образом, ДАТА и ЧИСЛО можно легко преобразовать в их символьный эквивалент. Такая конвертация известна как преобразования число в строку и дата в строку. Рассмотрим следующие запросы

     

    Query 1: select length(1234567890) from dual

    Query 2: select length(SYSDATE) from dual

     

    Оба запроса используют функцию LENGTH у которой входной параметр определён как строка. Число 1234567890 в запросе один неявно конвертируется в строку ‘1234567890’ перед вычисление функции LENGTH и результат функции будет 10. Запрос номер два вычисляет функцию SYSDATE предположим 7 апреля 2008 года. Результат преобразуется в строку ’07-APR-08’ и результат выполнения функции LENGTH будет число 9.

    Обычно не принято допускать неявную конвертацию строк в числа, так как единственная ситуация, когда это возможно, это если строка представляет собой валидное число. Строка ‘11’ будет неявно преобразована в число 11, но строка ’11.123.345’ не будет, как показано в следующих примерах

     

    Query 3: select mod(’11’, 2) from dual

    Query 4: select mod(‘11.123’, 2) from dual

    Query 5: select mod(‘11.123.456’, 2) from dual

    Query 6: select mod(‘$11’, 2) from dual

     

    Запросы 3 и 4 неявно преобразовали строки ‘11’ и ’11.123’ в числа 11 и 11.123 соответственно, перед вызовом функции MOD которая в свою очередь вернула результат 1 и 1.123. Запрос 5 вернул ошибку ‘ORA-1722: invalid number’, когда Oracle попытался неявно преобразовать строку в число, так как ‘11.123.456’ не является корректным числом. Запрос 6 также вернул ошибку так как символ доллара не может бять неявно преобразован в число.

    Неявная конвертация строки в дату возможна, когда строка удовлетворяет следующим шаблонам: [D|DD] separator1 [MON|MONTH] separator2][R|RR|YY|YYYY], где D и DD это день MON первые три буквы месяца, MONTH – полное название месяца. R и RR YY и YYYY отображают одну, две и четыре цифры года соответственно. Параметром separator1 и separator2 может быть практически любой спец символ, включая сюда пробел, табуляцию, знаки пунктуации и т.д. Таблица 10-2 показывает неявную конвертацию строки в дату, включая вызов функций работы с датами и результаты. Эти результаты предполагают, что система использует американскую локаль.

    5

     

    TIP Несмотря на то что неявная конвертация типов доступна, лучше использовать явный вызов функции конвертации перед использование данным в других функциях. Конвертация строки в число и дату использует маску форматирования.

     

    Явная конвертация типов данных

     

    Функции, которые конвертирует значение из одного типа данных в другой известны как явное преобразование типов. Они возвращают значение, которое будет гарантировано нужного типа данных и являются надёжным методом конвертации данных.

    Число и дату можно явно конвертировать в строку используя функцию TO_CHAR. Строку можно явно конвертировать в число используя функцию TO_NUMBER. Функция TO_DATE используется для конвертации строку в DATE. Маски форматирования Oracle позволяют гибко контролировать процесс конвертации строки в число или дату.

     

    Exam tip

    Понимание широко используемых масок форматирования проверяется достаточно просто вопросами вида: какой результат вернёт вызов функций TO_CHAR(TO_DATE(’01-JAN-00′,’DD-MON-RR’),’Day’).

     

    Использование функций TO_CHAR, TO_NUMBER и TO_DATE

     

    При сертификации очень часто используются вопросы о функциях TO_NUMBER, TO_DATE и TO_CHAR с примерами для анализа. Обсуждение функции TO_CHAR разделим на две части: конвертация даты в строку и конвертация числа в строку. Такое разделение основано на том что для разных типов данных доступны разные маски форматирования. Помимо этих функций существует много других, но эти используется наиболее часто.

     

    Использование функций конвертации

     

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

    Таблица 10-3 показывает синтаксис строчных функций конвертации данных

    6

    Необязательный параметр поддержки национального формата (nls_parameters) полезен для указания языка и форматирования, в котором названия дней, месяцев и разделители разрядов, целой и дробной части заранее предопределены. На рисунке 10-2 отображено представление NLS_SESSION_PARAMETERS которое содержит значения параментов NLS для текущей сессии. По умолчанию значение NLS_CURRENCY – знак доллара, но это можно изменить на уровне сессии. Например, для изменения символа валюты на строку ‘GBP’ можно выполнить запрос

    ALTER SESSION SET NLS_CURRENCY=’GBP’

     

    7

    Рисунок 10-2 – Представление NLS_SESSION_PARAMETERS

     

    Конвертация числа в строку используя функцию TO_CHAR

     

    Функция TO_CHAR возвращает значение типа VARCHAR2. Когда входных параметром является число то доступны некоторые параметры форматирования. Синтаксис команды TO_CHAR(num, [format], [nls_parameter]). Параметр num обязательный и должен быть числом. Необязательный параметр format можно использовать для указания информации о форматировании, такой как длина, символ валюты, позиция разделителя дробной и целой части и разделитель разрядов (три разряда) и должен быть заключен в одинарные кавычки. Доступны различные опции форматирования и часть из них представлена в таблице 10-4. Рассмотрим два запроса

     

    Query 1: select to_char(00001)||’ is a special number’ from dual;

    Query 2: select to_char(00001, ‘0999999’)||’ is a special number’ from dual;

     

    В запросе номер один у числа 00001 убираются ведущие нули, значение преобразуется в строку ‘1’ и возвращается результат ‘1 is a special number’. Зпрос номер два использует маску форматирования ‘0999999’ для числа 00001 преобразуя число в строку ‘0000001’ и возвращая результат ‘0000001 is a special number’. 0 и 6 девяток в маске форматирования указывают функции TO_CHAR что необходимо использовать ведущие нули, и длина строки должна быть 7. Таким образом строка, возвращаемая функцией TO_CHAR содержит семь символов.

    8

     

    Tip Конвертация чисел в строки надёжный способ убедиться что функция и SQL запрос в целом, который ожидает символьного значения, не вернёт ошибку когда встретится число. Конвертация чисел в строки часто используется для форматирования значений для отчетов. Маска форматирования поддерживает символ валюты, разделитель порядков и разделитель целой и дробной части, что часто используется при отображении финансовой информации.

     

    Конвертация даты в строку используя функцию TO_CHAR

     

    Вы можете использовать преимущества модели масок форматирования при конвертации ДАТЫ в практически любой вариант отображения даты как символьного значения используя функцию TO_CHAR. Синтаксис функции TO_CHAR(date1, [format], [nls_parameter]).

    Только параметр date1 обязательный; тогда он должен быть значением, которое может неявно преобразоваться в строку. Необязательный параметр format регистрозависимый и должен быть обрамлён одинарными кавычками. Маска форматирования указывает какие лементы даты должы быть выбраны и как отображать названия элементов даты: полные названия или аббревиатуры. Названия дней и месяцев автоматически разделяются пробелом. Такое поведение можно изменить, используя параметр маски fill mode (fm). Указав в начале маски параметр fm, вы укажете Oracle о необходимости убрать все пробелы. Доступно много опций для маски форматирования, часть из которых отображена в таблице 10-5. Рассмотрим три запроса

     

    Query 1: select to_char(sysdate)||’ is today»s date’ from dual;

    Query 2: select to_char(sysdate,’Month’)||’is a special time’ from dual;

    Query 3: select to_char(sysdate,’fmMonth’)||’is a special time’ from dual;

     

    Если текущая системная дата 3 января 2009 года и по умолчанию формат отображения DD/MON/RR тогда запрос один вернёт строку ‘03/JAN/09 is todays date’. Во втором запросе обратите внимание на две детали: во-первых, только месяц выбирается из даты, и во-вторых так как маска форматирования регистрозавсимая и в запросе используется ‘Month’, то запрос вернёт ‘January is a special time’. Нет нужды добавлять пробел в начале литерала, так как функция TO_CHAR автоматически добавит пробел к названию месяца. Если бы маска во втором запросе была ‘MONTH’ то запрос вернул бы ‘JANUARY is a special time’. Параметр fm в третьем запросе препятствует добавлению пробелов и результатом будет ‘Januaryis a special time’. В таблице 10-5 предполагается что обрабатывается дата 2 июня 1975 года и текущий год 2009.

    Параметры форматирования, связанные с неделей, кварталом, веком и другими более редко использующимися элементами даты показаны на рисунке 10-7. Столбец результата предполагает, что функция использовалась для работы с датой 24 сентября 1000 года, с маской форматирования указанной в столбец format element.

    Компонент время в типе данных дата выбирается, используя модели форматирования в таблице 10-7. Результат рассчитывается функцией TO_CHAR используя дату 27 июня 2010 года время 21:35:13 с маской форматирования указанной в столбце format element.

    Некоторые различные элементы, которые можно использовать в форматировании даты и времени перечислены в таблице 10-8. Знаки пунктуации используются для разделения элементов форматирования. Три типа суффиксов существуют для форматирования элементов. Более того, символьные литералы могут быть включены в модель форматирования если они заключены в двойные кавычки. Результаты в таблице 10-8 получены используя функцию TO_CHAR для даты 12 сентября 2008 года 14:31 с маской форматирования указанной в соответствующем столбце.

    9

    10 11 12

     

    Таблица JOB_HISTORY хранит информацию о должностях сотрудника, которые он занимал в компании. Запрос на рисунке 10-3 выбирает информацию из этой таблицы о конце срока действия должности сотрудника для каждого сотрудинка на основании столбцов END_DATE, EMPLOYEE_ID и JOB_ID и форматирует результат в красивое предложение. Символьное выражение объединяется с функцией TO_CHAR в которой используется маска ‘fmDay «the «ddth «of» Month YYYY’. Параметр fm используется чтобы убрать пробелы в имени дня недели и месяца. Два литерата ограниченые двойными кавычками используются для добавления читабельности результату. Литерал “th” применяется к элементу даты чтобы сделать литературно правильным отображение даты как 17th или 31th. ‘Month’ в маске означает использовать полное имя месяца и наконец YYYY форматирует год как все четыре символа года.

     

    13

    Рисунок 10-3 – Запрос в таблицу JOB_HISTORY

     

    select ‘Employee ‘||EMPLOYEE_ID||’ quit as ‘||JOB_ID||’ on ‘||TO_CHAR(END_DATE,’fmDay «the «ddth «of» Month YYYY’) «Quitting Date»

    FROM JOB_HISTORY

    ORDER BY END_DATE;

    Несмотря на то что компонент «век» не отображается по умолчанию, он хранится в базе данных и доступен для запроса. Маска форматирования DD-MON-RR используется по умолчанию для ввода значений и отображения. Когда значение добавляется или изменяется если явно неуказан век, то используется век из функции SYSDATE. Формат RR отличается от формата YY и так как RR также использует значение столетия. Влияние значения столетия на формат RR легче понять если рассмотреть следующие принципы

    • Если две последние цифры текущего года между 0 и 49, а в указанном значении даты две последние цифры года между 50 и 99 то используется предыдущий век. Предположим, что текущая дата 2 июня 2007 года. Значение века для даты 24-JUNE-94 года будет 20
    • Если две цифры текущего года между 50-99 и указанной даты также между 55 и 99, то возвращается текущий век. Преположим что текущая дата 2 июня 1975 года. Тогда значение века для 24-JUL-94 будет 20.
    • Если две цифры текущей даты между 50 и 99, а в укащанной дате год между 0 и 49 – то считается следующий век. Предположим, что текущая дата 2 июня 1975 года, тогда для значения 24-JUL-07 значение века будет 21.

     

    Конвертация строки в дату используя функцию TO_DATE

     

    Функция TO_DATE возвращает значение типа данных DATE. Строка, конвертируемая в дату может содержать все или часть компонентов, составляющих тип DATE. Когда строка содержащая только часть компонентов даты преобразуется в дату, Oracle использует значение по умолчанию для составления валидного значения типа DATE. Части строки сопоставляются с элементами даты используя маску (или модель) форматирования. Синтаксис функции TO_DATE(string1, [format], [nls_parameter]).

    Только параметра string1 обязателен, и eсли маска форматирования не указана, string1 должна быть в формат неявно конвертируемом в дату. Необязательный параметр format используется практически всегда и должен быть заключён в одинарные кавычки. Маска форматирования идентича перечисленным в таблицах 10-5, 10-6, и 10-7. У функции TO_DATE есть модификатор fx, которые используется подобно параметру fm функции TO_CHAR. Параметр fx требует обязательного совпадения строки и маски форматирования. Если строка не совпадает с маской – возвращается ошибка. Рассмотрим несколько примеров

     

    Query 1: select to_date(’25-DEC-2010′) from dual;

    Query 2: select to_date(’25-DEC’) from dual;

    Query 3: select to_date(’25-DEC’, ‘DD-MON’) from dual;

    Query 4: select to_date(’25-DEC-2010 18:03:45′, ‘DD-MON-YYYY HH24:MI:SS’) from dual;

    Query 5: select to_date(’25-DEC-10′, ‘fxDD-MON-YYYY’) from dual;

     

    Запрос 1 преобразует строку ’25-DEC-2010’ и строка может быть преобразована в дату используя маску DD-MON-YYYY. Дефис можно заменить на другой разделитель. Так как не было указано никакой информации о времени то используется значение по-умолчанию 00:00:00. Запрос 2 не может неявно преобразовать строку в дату, так как недостаточно информации и возвращается ошибка ORA-01840: input value is not long enough for date format. Указав маску DD-MON для строки ’25-DEC’ в запросе номер три, Oracle может преобразовать значение в дату, но так как год и время не указаны, в значении года будет использоваться значение года функции SYSDATE, а время установлено в полночь. Если текущий год будет 2009, то запрос 3 вернёт дату 25/DEC/09 00:00:00. Запрос 4 преобразует строку с явно указанными всеми компнонентами даты и времени. Запрос 5 использует параметра fx. Так как год в строке указан двумя символами, а требуемый формат предполагает четыре цифры года, то запрос возвращает ошибку ORA-01862: the numeric value does not match the length of the format item.

     

    Конвертация строки в число используя функцию TO_NUMBER

     

    Функция TO_NUMBER возвращает значение типа данных NUMBER. Исходная строка должна быть составлена таким образом, чтобы все несовместимые символы отсутствовали или были указаны в соответствующей маске форматирования. Синтаксис функции TO_NUMBER(string1, [format], [nls_parameter]). Только string1 является обязательным параметром, и если не указан параметр format то значение должно быть таким, чтобы была возможность неявно сконвертировать его в число. Маски форматирования идентичны перечисленным в таблице 10-4. Рассмотрим запросы

     

    Query 1: select to_number(‘$1,000.55’) from dual;

    Query 2: select to_number(‘$1,000.55′,’$999,999.99’) from dual;

     

    Запрос один не может неявно преобразовать строку, так как она содержит знак валюты и разделители, которые явно неуказаны в маске, поэтому возвращается ошибка ORA-1722: invalid number. Запрос два находит символ валюты, запятой и точки в маске форматирования и несмотря на то что длина маски больше чем чем исходное значение в строке, возвращается число 1000.55

     

    Exam tip

    Функция TO_NUMBER конвертирует значение строки в число. Если вы используете число длиннее чем маска, возвращается ошибка. Если вы конвертируете число используя более длинную маску – возвращается значение исходной длины. Не путайте TO_NUMBER с TO_CHAR. Например TO_NUMBER(‘123.45’,’999.9’) вернёт ошибку, когда TO_CHAR(123.45,’999.9’) вернёт 123.6

  • Использование символьных, строковых функций и функций работы с датой в SQL

    Функции, которые мы обсудим в этой части обычно используют встроенные PL/SQL код, сгруппированный в пакеты и поставляемый Oracle. Некоторые обрабатывают численные, символьные значения и значения даты, другие преобразуют данные в различные типы данных. Функции могут использовать вложенные вызовы и некоторые функции предназначены для работы со значением NULL. Функции условия CASE и DECODE позволяют отображать различный результат в зависимости от значений данных, что предоставляет возможность ветвления в контексте SQL запроса

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

     

    Определение функции

     

    Функция – это программа, которая может принимать (но необязательно) входные параметры, выполнять какие-либо операции и возвращать значение-литерал. Функция возвращает только одно значение за вызов.

    Три важных компонента формируют базис определения функции. Первый – это список входных параметров. Он определяет ноль или более параметров, которые могут передаваться функции для обработки. Эти параметры, или аргументы, могут быть необязательными (иметь значение по умолчанию) и быть разными типами данных. Второй компонент – это тип данных вовзращаемого результата. После выполнения, только одно значение предопределенного типа данных возвращается функцией. Третий компонент инкапсулирует детали обработки выполняемой функцией и содержит программный код, который работает с входными параметрами, производит вычисления и возвращает значение.

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

    Вызовы функций могут быть вложенными, к примеру, как F1(x, y, F2(a, b), z), где функция F2 принимает два входных параметра и возвращает третий из четырёх параметров для функции F1. Функции могут работать с любыми типами данных: наиболее часто используемые это символьные и числовые данные, а также данные типа дата. Этими параметрами функции могут быть столбцами или выражениями.

    Как пример можно рассмотреть функцию, которая рассчитывает возраст человека. Функция AGE принимает только один параметр, день рождения. Результат возвращаемый функцией AGE это число отображающее возраст человека. Расчёты черного ящика влючают в себя получение разницы в годах между текущей датой и днём рождения, переданным в качестве входного параметра.

     

    Типы функций

     

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

     

    Строчные функции

     

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

    Следующий запрос выбирает два столбца из таблицы REGIONS и выражение использующее функцию LENGTH и столбец REGION_NAME

     

    select region_id, region_name, length(region_name) from regions;

     

    Длина значения столбца REGION_NAME рассчитывается для каждой из четырёх строк в таблице REGIONS; функция выполняется четыре раза, возвращая каждый раз значение-литерал.

    Строчные функции работают работают с данными элементами строки для выборки и форматирования их перед отображением. Входными значениями строчной функции может быть определенная пользователем константа или литерал, данные столбца, переменные или выражения, возможно использующие другифе вложенные строчные функции и т.д. Вложенные вызовы часто используемая техника. Функции могут возвращать значение типа данных, отличного от типа данных входных параметров. Прерыдущий запрос показывает, как функция LENGTH принимает входным значением строку и возвращает число.

    Помимо использования функций в разделе SELECT строчные функции можно использовать в разделах WHERE и ORDER BY.

     

    Функции, работающие с набором данных

     

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

     

    Использование функций, изменяющих регистр

     

    Данные в таблицах могут заполняться из различных источников: программ, криптов и так далее. Не стоит полагаться что символьные данные будут вводиться в заранее определенном регистре. Строчные функции, изменяющие регистр предназначены для двух важных задач. Их можно использовать, во-первых, для изменения регистра данных при сохранении или выводе информации, либо в условиях WHERE для более гибкого поиска. Гораздо легче искать строку используя фиксированный регистр, вместро проверки всех комбинаций верхнего и нижнего регистра. Помните, что вызов функций не изменяет данные, которые хранятся в таблице. Они преобразуют данные результата запроса.

    Входными параметрами могут быть символьные литералы, столбцы символьного типа данных, символьные выражения или числа и даты (которые неявно будут преобразованы в строки).

     

    Функция LOWER

     

    Функция LOWER заменяет все символы прописного регистра на эквивалентные символы строчного регистра. Синтакис функции LOWER(string). Рассмотрим пример запроса использующего эти функции

     

    select lower(100+100), lower(‘SQL’), lower(sysdate) from dual

     

    Преположим что текущая дата 17 декабря 2015 года. Результатом запроса будут строки ‘200’, ‘sql’ и ‘17-dec-2015’.  Численное выражение и дата неявно преобразуются в строку перед вызовом функции LOWER.

    В следующем примере функция LOWER используется для поиска строк где буквы ‘U’ и ‘R’ в любом регистре идут друг за другом

     

    select first_name, last_name, lower(last_name) from employees

    where lower(last_name) like ‘%ur%’;

     

    Можно написать аналогичный запрос без использования функции LOWER. Например так

     

    select first_name, last_name from employees

    where last_name like ‘%ur%’ or last_name like ‘%UR%’

    or last_name like ‘%uR%’ or last_name like ‘%Ur%’

     

    Этот запрос работает, но он слишком громоздкий, и количество операторов OR возрастает экспоненциально по мере увеличения строки.

     

    Функция UPPER

     

    Функция UPPER логическая противоположность функции LOWER и заменяет все строчные символы на их прописные эквиваленты. Синтаксис функции – UPPER(string). Рассмотрим пример

     

    select * from countries where upper(country_name) like ‘%U%S%A%’;

     

    Этот запрос выбирает строки из таблцы COUNTRIES где COUNTRY_NAME содержит буквы ‘U’, ‘S’, ‘A’ в любом регистре в этом порядке.

     

    Функция INITCAP

     

    Функция INITCAP часто используется для отображения данных. Первые символы каждого слова в строке преобразуются к верхнему регистру, все остальные символы преобразуются в строчные эквиваленты. Под словом подразумевается набор символов не содержащих пробелов и спецсимволов. Пробел, символ подчеркивания а также спецсимволы такие как знак процента, восклицательные знак, знак доллара расцениваются как разделители. Функция INITCAP принимает один параметр и синтаксис INITCAP(string). Следующий пример показывает пример использования функции INITCAP

     

    select initcap(‘init cap or init_cap or init%cap’) from dual

     

    Результатом этого запроса будет строка Init Cap Or Init_Cap Or Init%Cap

     

    Использование функций работы со строками

     

    Функции работы со строками одна из самых мощных возможностей, предоставляемых Oracle. Они очень полезны и понятны практически без детальных объяснений и очень часто используются разными программистами при обработке данных. Часто используются вложенные вызовы этих функций. Оператор конкатенации может использоваться вместо функции CONCAT. Функции LENGTH, INSTR, SUBSTR и REPLACE могут дополнять друг друга, так же как RPAD, LPAD и TRIM.

     

    Функция CONCAT

     

    Функция CONCAT объединяет два литерала, столбца или выражения для составление одного большого выражения. У функции CONCAT два входных параметра. Синтаксис функции CONCAT(string1, string2) где string1 и string2 могут быть литералом, столбцом или выражением результат которого символьный литерал. Следующий пример показывает использование функции CONCAT

     

    select concat(‘Today is:’,SYSDATE) from dual

     

    Второй параметр функции это функция SYSDATE, которая возвращает текущее системное время. Значение преобразуется в строку и к ней присоединяется первый параметр. Если текущая системная дата 17 Декабря 2015 года, то запрос вернёт строку ‘Today is:17-DEC-2015’.

    Рассмотрим как использовать функция для объединения трех элементов. Так как функция CONCAT может принимать только два входных параметра, то можно объединить только два элемента. В таком случае можно использовать вызов функции как параметр другово вызова функции. Тогда запрос будет выглядеть так

     

    select concat(‘Outer1 ‘, concat(‘Inner1′,’ Inner2′)) from dual;

     

    У первой функции два параметра: первый параметр это литерал ‘Outer1 ‘, а второй параметра это вложенная функция CONCAT. Вторая функция принимает два параметра: литерал ‘Inner1’ и литерал ‘ Inner2’. Результатом выполнения этого запроса будет строка ‘Outer1 Inner1 Inner 2’. Вложенные функции расмотрим чуть позже.

     

    Функция LENGTH

     

    Функция LENGTH возвращает число символов которые составляют строку. Пробелы, табуляция и специальные символы учитываются функцией LENGTH. У функции один параметра и синтаксис LENGTH(string). Рассмотрим запрос

     

    select * from countries where length(country_name) > 10;

     

    Функция LENGTH используется для выбора тех стран у которых длина названия больше чем десять символов.

     

    Функции RPAD и LPAD

     

    Функции RPAD и LPAD возвращают строку фиксированной длины и при необходимости дополняют исходное значение определенным набором символов слева или справа. Символами используемые для добавления могут быть литерал, значение столбца, выражение, пробел (значение по умолчанию), табуляция и спец символы. Функции LPAD и RPAD принимают три входных параметра и синтаксис LPAD(s, n, p) и RPAD(s, n, p) где s – значение строки для обработки, n – количество символов результата и p – символы для добавления. Если используется LPAD, то символы p добавляются слева до достижения длины n. Если RPAD – то справа. Обратите внимание что если длина s больше чем длина n – то результатом будет первые n символов значения s. Рассмотрим запросы на рисунке 10-1

    1

    Рисунок 10-1 – Использование функций RPAD и LPAD

     

    Первый запрос не изменяет данные и результат не очень читабельный по сравнению с результатом второго запроса. RPAD используется для добавления пробелов там где необходимо для first_name и last_name чтобы все значения были фиксированной длины в 18 символов, и LPAD используется для добавления пробелов в начало значения salary до достижения длины 6 символов.

     

    Функция TRIM

     

    Функция TRIM убирает символы и начала или окончания строки чтобы сделать её потенцильно короче. Функция принимает обязательный параметр и необязательный. Синтаксис функции TRIM([trailing|leading|both] trimstring from string). Параметр входная строка (s) обязательный. Следующие пункты перечисляют параметры

    • TRIM(s) убираются пробелы в начале в к конце строки
    • TRIM(trailing trimstring from s) убирает символы trimgstring в конце строки
    • TRIM(leading trimstring from s) убирает символы trimgstring в начале строки
    • TRIM(both trimstring from s) OR TRIM(trimstring from s) убирают все символы trimstring в начале и в конце строки

     

    Запрос

     

    select trim(both ‘*’ from ‘****Hidden****’),

    trim(leading ‘*’ from ‘****Hidden****’),

    trim(trailing ‘*’ from ‘****Hidden****’) from dual;

     

    Вернёт “Hidden”, “Hidden****”, и “****Hidden”. Обратите внимание что, указав всего один символ, все символы убираются если они последовательно повторяются.

    Функция INSTR

     

    Функция INSTR ищет подстроку в строке. Возвращается число, обозначающее позицию откуда n-ное вхождение начинается, начиная с позиции поиска, относительно начала строки. Если подстрока не найдена в строке – возвращается 0.

    У функции INSTR два параметра обязательных и два параметра необязательных. Синтаксис функции INSTR(source string, search string, [search start position], [n occurrence]). Значение по умолчанию для search start position=1 или другими словами начало строки source string. Значение по умолчанию для n occurrence=1 или первое вхождение. Рассмотрим несколько примеров

     

    Query 1: select instr(‘1#3#5#7#9#’, ‘#’) from dual;

    Query 2: select instr(‘1#3#5#7#9#’, ‘#’ ,5) from dual;

    Query 3: select instr(‘1#3#5#7#9#’, ‘#’, 3, 4) from dual;

     

    Первый запрос ищет первое вхождение хеш-тега в строке и возвращает значение 2. Второй запрос ищет хеш-тег в строке начиная с пятого символа и находит первое вхождение с 6 символа. Третий запрос ищет четвертое вхождение хеш-тега начиная с третьего символа и находит его в позиции 10.

     

    Функция SUBSTR

     

    Функция SUBSTR возвращает подстроку определённой длины из исходной строки начиная с определённой позиции. Если начальная позиция больше чем длина исходной строки – возвращается значение NULL. Если длины исходной строки недостаточно для получения значения необходимой длины начиная с определённой позиции, то возвращается часть строки с исходного символа до конца строки.

    У функции SUBSTR три параметра, первые два обязательны и синтаксис SUBSTR(source string, start position, [number of characters]). Значение по умолчанию для characters to extract = разница между длиной source string и start position. Рассмотрим следующие примеры

     

    Query 1: select substr(‘1#3#5#7#9#’, 5) from dual;

    Query 2: select substr(‘1#3#5#7#9#’, 5, 3) from dual;

    Query 3: select substr(‘1#3#5#7#9#’, -3, 2) from dual;

     

    Запрос 1 возвращает подстроку начиная с позиции 5. Так как третий параметр не указан, количество символов равно длине исходной строки минус начальная позиция и будет равно шести. Первый запрос вернёт подстроку ‘5#7#9#’. Запрос два возвращает три символа начиная с пятого символа и строка результат будет ‘5#7’. Запрос три начинается с позиции минус три. Отрицательная начальная позиции говорит Oracle о том, что начальная позиция рассчитывается от конца строки. Таким образом начальная позиция будет длина строки минус три и равна 8. Третий параметр равен двум и возвращается значение ‘#9’.

     

    Функция REPLACE

     

    Функция REPLACE заменяет все вхождения искомого элемента на значение строки для подстановки. Если длина заменяемого элемента не равна длине элемента, на который происходит замена, длина получаемой строки будет отличной от исходной строки. Если искомая подстрока не найдена, строка возвращается без изменений. Доступно три параметра, два первых обязательные и синтаксис вызова REPLACE(source string, search element, [replace element]). Если явно не указать параметр replace element, то из исходной строки удаляются все вхождения search element. Другими словами, replace element равно пустой строке. Если все символы исходной строки заменяются пустым replace element возвращается NULL. Рассмотрим несколько запросов

     

    Query 1: select replace(‘1#3#5#7#9#’,’#’,’->’) from dual

    Query 2: select replace(‘1#3#5#7#9#’,’#’) from dual

    Query 3: select replace(‘#’,’#’) from dual

     

    Хеш в первом запрос обозначает символ для поиска и строка для замены ‘->’. Хеш появляется в строке пять раз и заменяется, получаем итоговую строку ‘1->3->5->7->9->’. Запрос 2 не указывает явно строку для замены. Значением по умолчанию является пустая строка и результатом будет ‘13579’. Запрос номер три вернёт NULL.

     

    Использование численных функций

     

    В Oracle доступно множество встроенных функций для работы с числами. Существенной разницой между численными функция и другими является то, что эти функции принимают параметрами только числа и возвращают только числа. Oracle предоставляет численные функции для работы с тригонометрическими, экспоненциальными и логарифмическими выражениями и со многими другими. Мы сфокусируемся на простых численных строчных функциях: ROUND, TRUNC и MOD.

     

    Функция ROUND

     

    Функция ROUND округляет число в зависимости от необходимой точности. Возвращаемое значение округляется либо в большую, либо в меньшую сторону, в зависимости от значения последней цифры в необходимом разряде. Если значение точности n, то цифра, которая будет округляться будет на позиции n после запятой, а значение будет зависеть от цифры на позиции (n+1). Если значение точности отрицательное, то все цифры после разряда n слева от запятой будут 0, а значение n будет зависеть от n+1. Если значение цифры от которой зависит округление больше или равно 5, то округление происходит в большую сторону, иначе в меньшую.

    Функция ROUND принимает два входных параметра и синтаксис ROUND(source number, decimal precision). Source number может быть любым числом. Параметр decimal precision определяет необходимую точность и необязателен. Если этот параметр не указан, значение по умолчанию будет 0, что обозначает необходимость округления до ближайшего целого числа.

    Рассмотрим таблицу 10-1 для числа 1601.916. Отрицательные значения точности находятся слева от точки (целая часть), когда положительные считаются вправо от точки (дробная часть).

    2

     

    Если значение точности единица, значение округляется до десятка. Если два, то значение округляется до второго порядка и т.д. Следующие запросы отображают использование этой функции

     

    Query 1: select round(1601.916, 1) from dual;

    Query 2: select round(1601.916, 2) from dual;

    Query 3: select round(1601.916, -3) from dual;

    Query 4: select round(1601.916) from dual;

     

    Первый запрос использует параметр точности равные единице, что означает что число будет округлено до ближайшей десятой. Так как значение сотой части равно единице (меньше чем 5), то происходит округление в меньшую сторону и возвращается значение 1601.9. Точность второго запроса равна двойке, таким образом значение окружается до сотой. Так как значение тысячной части равно 6 (что больше 5), то значение сотой части округляется вверх и возвращается значение 1601.92. Значение параметра точности в третьем запросе равно минус трём. Так как значение отрицательное, это значит, что округление будет происходить, основываясь на значении третьей позиции слева от точки, во втором разряде (сотни), и значение 6. Так как 6 больше пяти, то происходит округление вверх и возвращается значение 2000. Запрос 4 вызывает функцию без параметра точности. Это означает что число округляется до ближайшего целого. Так как десятая часть равна 9, то значение округляется в большую сторону и возвращется значение 1602.

     

    Численная функция TRUNC

     

    Функия TRUNC сокращает значение числа основываясь на значение параметра точности. Сокращение отличается от округления тем, что при сокращении лишняя часть просто отрезается и не происходит никаких изменений остальных цифр числа. Если значение точности отрицательное, то входное значение сокращается на позиции слева от запятой. Синтаксис функции TRUNC(source number, decimal precision). Параметром source number может быть любое число и этот параметр обязателен. Параметр decimal precision определяет позицию округления и не обязателен, значением по умолчанию будет ноль, что означает сокращение до целого числа.

    Если значение decimal precision равно одному, то число сокращается до десятых, если два, то до сотых и так далее. Рассмотрим несколько примеров использования этой функции

     

    Query 1: select trunc(1601.916, 1) from dual;

    Query 2: select trunc(1601.916, 2) from dual;

    Query 3: select trunc(1601.916, -3) from dual;

    Query 4: select trunc(1601.916) from dual;

     

    В запросе 1 используется точность равная единице, что значит сокращение значения до десятых и возвращается значение 1601.9. Точность во втором запросе равна двум, исходное значение сокращается до сотых и возвращается значение 1601.91. Обратите внимание что получаемое значение будет отличаться от значения, возвращаемого функцией ROUND с такими же параметрами, так как при вызове ROUND произойдёт округление в большую сторону (6 больше 5). В запросе номер три используется отрицательное число как значение параметра точности. Позиция три слева от запятой означает что сокращение будет до третьего разряда (сокращаются сотни) как показано в таблице 10-1 и возвращаемое значение будет 1000. И наконец в четвертом запросе явно неуказано значение точности и сокращается дробная часть исходного числа. Результатом будет 1601.

     

     

     

     

    Функция MOD

     

    Функция MOD возвращает остаток от деления. Два числа, делимое (число которое делится) и делитель (число на которое делится) определяются как параметры и вычисляется операция деления. Если делимое делится на делитель нацело, то возвращается ноль, так как нет остатка. Если делитель ноль, то не происходит ошибки деления на ноль, а возвращается делимое. Если делитель больше чем делимое, возвращается делимое.

    У функции MOD два входные параметра и синтаксис MOD(dividend, divisor). Параметры dividend и divisor могут быть численными литералами, столбцами или выражениями и могут быть положительными или отрицательными. Следующие примеры показывают использование этой функции

     

    Query 1: select mod(6, 2) from dual

    Query 2: select mod(5, 3) from dual

    Query 3: select mod(7, 35) from dual

    Query 4: select mod(5.2, 3) from dual

     

    В запросе один 6 делится на два нацело без остатка и возвращается 0. В запросе два 5 делится на 3, целая часть будет 1 и возвращается остаток 2. В запросе номер три семь делится на 35. Так как делитель больше чем делимое – возвращается делимое, т.е. целая часть 0. Запрос четыре использует дробное число как делимое. Целой частью будет один и остаток будет 2.2.

     

    Tip

    Любое чётное число делится на два без остатка, любое нечётное число при делении на два вернёт остаток 1. Поэтому функцию MOD часто используют чтобы отличать чётные и нечётные числа.

     

    Работа с датами

     

    Функции работы с датами предлагают удобный способ решать задачи, связанные с датами без необходимости учитывать высокосные года, сколько дней в конкретном месяце. Вначале рассмотрим, как хранятся данные типа дата и форматирование даты, а также функцию SYSDATE. Затем рассмотрим функции ADD_MONTHS, MONTHS_BETWEEN, LAST_DAT, NEXT_DAY, ROUND и TRUNC.

     

    Хранение даты в базе данных

     

    База данных хранит данные как число, которое способно поддерживать расчёт века, года, месяца и дня, а также информации о времени, такой как час, минута и секунда. Когда происходит запрос к данным, на число накладывается определённое форматирование (маска), и по умолчанию маска отображает день, три первых буквы названия месяца и две цифры, отображающие год.

     

    Функция SYSDATE

     

    Функция SYSDATE не использует входные параметры и возвращает текущее время и дату установленную на сервере БД. По умолчанию функция SYSDATE возвращает дату в формате DD-MON-RR и отображает дату на сервере. Если сервер установлен в другом часовом поясе чем машина клиента, то время и дата, возвращаемые SYSDATE могут отличаться от локальных значений на клиентсой машине. Можно выполнить такой запрос для отображения системной даты на сервере

     

    select sysdate from dual

     

    Арифметика над датами

     

    Следуещее уравнение отображает важный принцип при работе с датами

    Date1 – Date2 = Num1

    Дата может вычитаться из другой даты. Разница между двуми датами понимается как количество дней между ними. Любое число, включая дробные, может быть добавлено или вычтено из даты. В этом контексте число представляет собой количество дней. Сумма или разница между число и датой – это всегда дата. Этот принцип подразумевает что сложение, умножение или деление двух дат невозможен.

     

    Функция MONTHS_BETWEEN

     

    Функция MONTHS_BETWEEN возвращает количество месяцев между двумя обязательными входными параметрами. Синтаксис функции MONTHS_BETWEEN(date1, date2). Функция рассчитывает разницу между date1 и date2. Если date1 меньше чем date2, то возвращается отрицательное число. Возвращаемое значение может состоять из целой части, отражающей количество месяцев между двумя датами, и дробной части, отражающей сколько дней и часов осталось (основываясь на месяце равном 31 дню) после вычета целого количества месяцев. Целое число вовзращается если день сравниваемых месяцев одинаковый или последний день соответствующего месяца.

    Следующие примеры используют функию MONTHS_BETWEEN

     

    Query 1: select months_between(sysdate, sysdate-31) from dual;

    Query 2: select months_between(’29-mar-2008′, ’28-feb-2008′) from dual;

    Query 3: select months_between(’29-mar-2008′, ’28-feb-2008′) * 31 from dual;

     

    Преположим что текущая дата 16 Апреля 2009. Запрос один вернёт один как количество месяцев между 16 апреля 2009 и 16 марта 2009. Запрос два неявно конвертирует литералы в даты используя формат DD-MON-YYYY. Так как часть о времени опущена Oracle установит значение времени 00.00.00 для обеих дат. Фукнция вернёт значение примерно равное 1.03225806. Целая часть результата обозначает что между датами один месяц. Между 28 февраля и 28 марта ровно один месяц. Тогда дробная часть должна показывать ровно один день. Результат включает в себя часы минуты и секунды, но в нашем случае временная составляющая дат одинаковая. Умножение 0.03225806 на 31 вернёт 1, так как дробная часть, возвращаемая MONTHS_BETWEEN, рассчитывается, допуская что месяц равен ровно 31 дню. Поэтому запрос номер три вернёт значение 32.

     

    Exam tip

    Популярной ошибкой является допущение что возвращаемый тип данных функции зависит от типа функции (функции работы с датой должны возвращать дату, функции обработки строк – строку). Это верное только для численных функций. Символьные функции и функции работы с датами могут возвращать значение любого типа данных. Например, INSTR явлется символьной функцией, а MONTS_BETWEEN функцией работы с датой, но обе они возвращают результатом число. Также часто ошибочно рассуждают что разница между датами – это дата, когда фактически это число.

     

    Функция ADD_MONTHS

     

    Функция ADD_MONTHS возвращает дату, полученную путём добавления определённого количества месяцев к исходной дате. У этой функции два обязательных параметра и синтаксис ADD_MONTHS(start date, number of months). Значение параметра number of months может быть отрицательным, тогда исходное значение будет уменьшаться на это количество месяцев и дробным, но учитываться будет только целая часть. Следующие три запроса показывают использование функции ADD_MONTHS

    Query 1: select add_months(’07-APR-2009′, 1) from dual;

    Query 2: select add_months(’31-DEC-2008′, 2.5) from dual;

    Query 3: select add_months(’07-APR-2009′, -12) from dual;

     

     

    Результатом первого запроса буде 7 мая 2009, так как день остаётся одинаковым если это возможно и месяц увеличивается на один. Во втором запросе число месяцев дробное, что игнорируется, то есть этот запроса равен ADD_MONTHS(’31-DEC-2008’,2). Добавление двух месяцев должно вернуть 31-FEB-2009, но такой даты не существует, поэтому возвращается последний день месяца. В последнем примере используется отрицательное число для параметра кол-во месяцев и возвращается дата 07-APR-2008 что на двенадцать месяцев раньше, чем исходное значение.

     

    Функция NEXT_DAY

     

    Функция NEXT_DATE возвращает следующий ближайший заданный день недели после исходной даты. У этой функции два обязательных параметра и синтаксис NEXT_DAY(start date, day of the week). Функция выичсляет значение, когда заданный day of the week наступит после start date. Параметр day of the week может быть задан как числом, так и строкой. Допустимые значения определяются параметром NLS_DATE_LANGUAGE и по умолчанию используются три первые буквы названия дня недели в любом регистре (SUN, mon etc) или целые числа где 1 равно воскресенью, 2 – понедельник и так далее. Также имена дней недели могут быть более чем три символа; например, воскресенье можно указать как sun, sund, Sunday. Рассмотрим несколько запросов

     

    Query 1: select next_day(’01-JAN-2009′, ‘tue’) from dual;

    Query 2: select next_day(’01-JAN-2009′, ‘WEDNE’) from dual;

    Query 3: select next_day(’01-JAN-2009′, 5) from dual;

     

    1 января 2009 года это четверг. Следущий вторник будет через 5 дней, 6 января 2009 года. Второй запрос вернёт 7 января 2009 – следующая среда после 1 января. Третий запрос использует число как параметр и если у вас установлены Американские значения, то пятый день — это четверг. Следующий четверг после 1 января ровно через неделю – 8 января 2009 года.

     

    Функция LAST_DAY

     

    Функция LAST_DAY возвращает дату последнего дня месяца исходной даты. Эта функция требует один обязательные параметр и синтаксис LAST_DAY(start date). Функция выбирает месяц исходной даты и затем расчитывает последний день месяца. Следующий запрос вернёт 31 января 2009 года

     

    select last_day(’01-JAN-2009′) from dual;

     

    Функция ROUND для работы с датами

     

    Функция ROUND округляет значение даты до заданной точности даты. Возвращаемое значение округляется либо к большему, либо r меньшему значению в зависимости от значения округляемого элемента. Эта функция требует один обязательный параметр и допускает один необязательные и синтаксис функции ROUND(source date, [date precision forma]). Параметром source data может быть любой элемент типа данных дата. Параметр date precision format определяет уровень округления и значение по умолчанию – день. Параметром date precision format может быть век (CC) год YYYY квартал Q месяц M неделя W день DD час HH минута MI.

    Округления до века эквивалентно добавление единицы к текущему веку. Округление до месяца будет в большую сторону если день больше 16 иначе будет округление до первого дня месяца. Если месяц от одного до шести округление будет до начала текущего года, иначе вернётся дата начала следующего года. Рассмотрим запрос

    3

    Предположим, что этот запрос был выполнен 17 апреля 2009 года в 00:05. Вначале происходит округление текущей даты до дня (параметр точности явно неуказан). Так как время 00:05 то день не округляется в большую сторону.Так как 1 апреля 2009 года это среда, то второй столбец вернёт среду той недели, в которую входит исходная дата. Первая среда недели, в которую входит 19 апреля – это 15 апреля 2009 года. Третий столбец оругляет месяц до следующего (так как 17 больше 16) и возвращает 01 мая 2009. Поледний столбец округляет дату до года и возвращает 1 явнваря 2009 года, так как апрель это 4ый месяц.

     

    Функция TRUNC при работе с датами

     

    Функция TRUNC сокращает дату основываясь на параметре точности. У этой функции один параметр обязательный и один нет и синтаксис вызова TRUNC(source date, [date precision format]). Параметром source date может быть любая валидная дата. Параметр date precision format определяет уровень сокращения даты и необязателен, значение по умолчанию – сокращение до дня. Это значит что все значения времени обнуляются – 00 часов 00 минут 00 секунд. Сокращение до месяца вернёт дату равную первому дню месяца исходной даты. Сокращение до года – вернёт первый день года исходной даты. Рассмотрим запрос, использующий функцию с разными параметрами

    4

    Этот запрос выполнятся 17 апреля в 00:05. Первый столбец сокращает системную дату до дня, время преобразуется из 00:05 в 00:00 (параметр точности явно неуказан, используется значение по умолчанию) и возвращается текущий день. Второй столбец сокращает дату до такого же дня недели, который был первого числа месяца (среда) и возвращает среду текущей недели – 15 апреля. Третий столбец сокращает дату до месяца и возвращает первый день месяца – 1 апреля. Четвертый столбец сокращает дату до года и возвращает первый день года.

  • Получение, ограничение и сортировка данных используя SQL — Итоги

    Возможности команды SELECT

    • Три операции доступные для команды SELECT это проекция, выборка и объединение
    • Проекция – это ограничение столбцов, выбираемых из таблцы. Используя проекцию вы получаете только столбцы в которых вы заинтересованы, вместо всех возможных.
    • Выборка используется во время вычитки строк из таблицы. Выборка включает наложение ограничений на выбираемые строки на основе критериев или условий. Это позволяет вам получать только те строки, которые вам необходимы
    • Объединение включает в себя связь таблиц основываясь на общиъ аттрибутах. Объединение позволяет хранить данные в третьей нормальной форме в разных таблицах вместо одной большой таблицы.
    • Команда DESCRIBE выводит список названий столбцов, их типов данных и ограничение обязательности

     

    Базовая команда SELECT

    • Директива SELECT определяет проекцию столбцов. Другими словами, SELECT определяет какие именно столбцы должны быть включены в результат
    • Ключевое слово DISTINCT препятствует возникновению строк, содержащих дубликаты всех столбцов в возвращаемом результате
    • Выражения и столбцы могут использовать псевдоним используя ключевое слово AS или пробел между столбцом или выражением и псевдонимом
    • Одиночная кавычка в символьном литерале может быть экранирована путём добавления дополнительной одинарной кавычки или используя оператор quote.

     

    Ограничение строк, получаемых запросом

    • Одно или более условий образуют раздел WHERE. Эти условия определяют правила, которые должны выполнять данные чтобы быть выбраны в результат
    • Для каждой строки, проверяемой в условии, есть операнды, которые находятся слева и справа от оператора. Операндом может быть значение столбца, литерал или выражение.
    • Операторы сравнения могут проверять данные по-разному. Равенство или неравенство проверяются очень часто, но доступны также операторы проверки диапазона, вхождения в группу и проверка на основании шаблона.
    • Булевыми операторами являются операторы AND, OR и NOT. Операторы AND и OR позволяют использовать несколько условий в разделе WHERE.
    • Оператор NOT меняет смысл оператора сравнения на противоположный.

     

    Сортировка строк, возвращаемых запросом

    • Результат можно сортировать, используя ключевое слово ORDER BY. Полученные строки могут быть отсортированы по одному или нескольким столбцам указав имя столбца или его порядковый номер в разделе SELECT
    • Вывод данных может быть отсортирован по возрастанию или убыванию используя ключевые слова DESC или ASC после каждого столбца или выражения исопльзуемого для сортировки.

     

    Подстановка переменной

    • Подстановка переменной позволяет использовать написанный ранее запрос добавляя возможность заменить некоторые элементы во время выполнения. Один и тот же запрос может быть выполнен несколько раз с указанием разных параметров.
    • Переменные сессии могут задаваться явно, используя команду DEFINE. Команда UNDEFINE позволяет удалить переменные сессии включая явно созданные командой DEFINE и неявно созданные (используя двойной амперсант).
    • Команда VERIFY управляет выводом пользователю запроса до и после подстановки переменной
  • Подстановка амперсанта

    Вы разработали хороший запрос и возможно захотите использовать его в будущем. Иногда полезно иметь заготовку запроса, в которой указаны переменные, которые будут заменены на значения при выполнении запросы. Oracle предоставляет такой функционал в виде так называемой заменты переменной (ampersand substitution). Каждый элемент команды SELECT может быть подставлен во время выполнения, и путём оставления в запросе только ключевых элементов и ввода динамических переменных вы можете избежать много скучной и повторяемой работы. Мы рассмотрим подстановку переменной и ключевые слова DEFINE и VERIFY.

     

    Замена переменных

     

    Замену переменных можно рассматривать как установку заглушек. SQL запрос состоит из двух или более частей. Каждую часть можно разбить на подчасти, которые состоят из текста. Любой текст, подчасть или часть можно указать как заглушку.

     

    Замена одиночным амперсандом

     

    Самая простая и популярная форма SQL элемента это замена одинарного амперсанта. Символ амперсанта (&) выбран для назначения переменной в запросе и переменная состоит из амперсанта и названия переменной без пробела между ними. Когда запрос выполняется, серверный процесс Oracle видит переменную для замены и пытается определить её значение двумя способами. Во первых просматривается определена ли переменная в сессии пользователя. (Команду DEFINE мы рассмотрим чуть позже). Если переменная не определена, то пользовательский процесс запрашивает значение на которое будет заменена сооветствующая переменная. После того как значение введено, запрос выполняется сервером Oracle. Замена переменной амперсанта происходит в момент выполнения запроса и иногда называется связывание во время выполнения  (runtime binding) или подстановка во время выполнения (runtime substitution).

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

     

    select employee_id, last_name, phone_number from employees

    where last_name = &LASTNAME or employee_id = &EMPNO;

    Когда вы запустите запрос, Oracle спросит входное значения для переменной с именем LASTNAME. Вы можете ввести фамилию сотрудника, если вы её знаете, например ‘King’. Если вы не знаете фамилию но знаете номер, вы можете ввести любой значение и нажать OK для ввода значения. Затем Oracle запросит значения для переменной EMPNO. После ввода значения, например 0, и нажатия OK, не остаётся переменных для замены и выполняется следующий запрос

     

    select employee_id, last_name, phone_number from employees

    where last_name = ‘King’ or employee_id = 0;

     

    Переменной можно назначить любой символьное значение с валидным именем. Значение-литерала на которое будет произведена замена должно быть соответственного типа данных, иначе вы получите ошибку “ORA-00904: invalid identifier”. Если переменная подразумевает символьное значение или значение данных, то литерал должен быть заключен в одинарные кавычки. Полезным способом избежать ошибки типа данных является обрамление переменной в кавычки при необходимости. Тогда пользователю нет необходимости знать о типе данных.

     

    select employee_id, last_name, phone_number from employees

    where last_name = ‘&LASTNAME’ or employee_id = &EMPNO;

     

    Двойной амперсант

     

    Когда переменная используется несколько раз в запросе, Oracle будет запрашивать значение каждый раз когда встречается переменная в запросе. Для сложных запросов, это может быть очень неэффективно и приводить к ошибкам. Следующий запрос выбирает FIRST_NAME и LAST_NAME из таблицы EMPLOYEES который содержит символы в обоих столбцах

     

    select first_name, last_name from employees

    where last_name like ‘%&SEARCH%’ and first_name like ‘%&SEARCH%’;

     

    Два условия одинаковые но они проверяются для разных столбцов. Когда запрос будет выполняться, вначале Oracle потребует ввод значения для переменной SEARCH используемом в первом условии со столбцом LAST_NAME. Затем потребуется ввод данных для замены значения переменной SEARCH используемом при сравнении с FIRST_NAME. Это привносит две проблемы. Во первых это неэффективно вводить одно и тоже значение два раза, и во вторых, что более важно, можно допустить опечатку при повторном вводе, так как Oracle не проверяет идентичность ввода значения для переменной. В этом примере, допущено логическое предположение что значение переменных должно быть одинаковым, но тот факт что у переменной одинаковое имя не значит для Oracle что значение должно быть одинаковым. На первом примере на рисунке 9-7 отображён результат выполнения запроса и ввода двух разных значений для подстановки переменной. В этом примере результат неверный, так как исходно требование было таким, что фамилия и имя сотрудника должны содержать одинаковые литералы.

    Когда подстановка переменной производится несколько раз в одном запросе, и вы знаете что значение должно быть одинаковым при каждом упоминании переменной, предпочтительнее использовать подстановку двойного амперсанта. Это требует ввода двух амперсантов перед именем переменной которая будет использоваться несколько раз. Когда Oracle видит двойной амперсант, назначается значение переменной сессии и вам не будет выводиться запрос при встрече переменной дальше в запросе.

    На втором примере на рисунке 9-7 показано как использовать переменную SEARCH с двумя амперсантами в условии для столбца LAST_NAME, а затем переменная с тем же именем и одним амперсантом не затребует ввода значения. Когда запрос будет выполняться, Oracle запросит значение для SEARCH только один раз установит значение переменной SEARCH для сессии введённое значение и будет использовать его дальше. Для того чтобы сбросить это значение вам необходимо будет выполнить команду UNDEFINE.

    1

     

    Рисунок 9-7 Использование двойного амперсанта

     

    Подстановка названий столбцов

     

    До этого мы обсуждали подстановку литералов в секции WHERE, но можно заменять любой элемент SQL запроса. В следующем примере столбцы FIRST_NAME и JOB_ID статическиу и будут возвращены в любом случае, но третий столбец это переменная для подстановки во время выполнения с именем COL. Результат также сортируется используя этот столбец-переменную указанную в директиве ORDER BY

     

    select first_name, job_id, &&col

    from employees

    where job_id in (‘MK_MAN’,’SA_MAN’)

    order by &col;

     

    В отличие от символьных литералов и литералов типа данных дата – имя столбца не нуждается в обрамлении одиночными кавычками ни во время определения ни во время указания значения.

     

    Подстановка выражений и текста

     

    Практически все элементы SQL запроса могут быть заменены во время выполнения. Ограничение, установленное Oracle – только первое слово должно быть статичным. В случае команды SELECT, минимальной командой будет ключевое слово SELECT, а всё остальное может быть заменено во время выполнения как в следующем примере

     

    select &rest_of_statement;

     

    Когда команда будет выполняться, будет выведен запрос для ввода значения для переменной с именем REST_OF_STATEMENT, которая добавится к слову SELECT. Лучшими кандидатами для использования подстановки переменных являются запросы, которые выполняются много раз, и незначительно отличаются друг от друга.

     

    Команды DEFINE и VERIFY

     

    Двойной амперсант используется чтобы избежать ввода значения несколько раз для одной и тоже переменной которая используется несколько раз в запросе. Когда встречается двойной амперсант, переменная сохраняется как переменная сессии. Когда запрос выполняется, все остальные вхождения переменной автоматически заменяются, используя сохраненную переменную. Все последующие выполнения запроса в той же сессии автоматически определяют значения переменной из переменной сессии. Это не всегда то что требуется и также ограничивает функционал подстановки переменной. Как-бы там ни было, Oracle предоставляет механизм для очистки переменных сессии. Команда VERIFY это команда с клиентской стороны и она контролирует будут или нет выводиться пользователю заменённые элементы перед выполнением запроса, который использует переменные.

     

    DEFINE и UNDEFINE

     

    Переменные сессии создаются, когда они встречаются в запросах использующих двойной амперсант. Они существуют всё время жизни сессии или пока они явно неудалены. Сессия завершается, когда пользователь выходит из клиентской программы к примеру, SQL *Plus, или, когда пользовательский процесс принудительно завершается.

    Проблема постоянно существующей переменной в том, что они скрывают смысл динамических запросов, использующих замену переменной. К счастью, переменные сессии можно удалить, используя команду UNDEFINE. Синтаксис команды для удаления переменной

     

    UNDEFINE variablename

     

    Рассмотрим простой динамический запрос, который выбирает статические столбцы и столбцы-переменные из таблицы EMPLOYEES и сортирует результат на основании столбца-переменной

     

    select last_name, &&COLNAME

    from employees where department_id=30 order by &COLNAME;

     

    Первый раз когда запрос будет выполняться, появится запрос на ввод значения для переменной COLNAME. Предположим вы ввели SALARY. Это значение подменяется и запрос выполняется. Все последующие выполнения этого запроса в той же сессии не будут запрашивать значения для переменной COLNAME, так как уже создалась переменная и её значение SALARY. Переменная может быть удалена командой UNDEFINE COLNAME. После того как переменная сессии удалена – следующее выполнение запроса заново запросит пользователя ввести значение для переменной COLNAME.

    У команды DEFINE два назначения. Её можно использовать чтобы просмотреть список всех переменных, установленных в текущей сессии, а также для явного задания значения переменной, используемой для подстановки в любых запросах на время жизни сессии. Синтаксис команды для двух этих вариаций

     

    DEFINE;

    DEFINE variable=value;

    Как показано на рисунке 9-8, переменная с именем EMPNAME явно определяется со значением ‘King’. Команда DEFINE без параметров возвращает список переменных сессии явно заданных и исользованных в запросах с двойным амперсантом.

    2

    Рисунок 9-8 – Пример использования команд DEFINE и UNDEFINE

     

    Затем выполняются два простых запроса в которых используется явно определённая переменная EMPNAME. Затем, переменная удаляется.

    Поддержка переменных-сессии может быть включена или отключена, когда необходимо с помощью команды SET DEFINE ON|OFF. Команда SET это не команда SQL, это команда управления окружением SQL. Если вы указываете SET DEFINE OFF, клиентская программа (к примеру, SQL *Plus) не сохраняет переменные сессии, а считает, что амперсант — это обычный литерал. Таким образом команда SET DEFINE OFF|ON управляет доступна ли замена переменной для вашей сессии. Следующий запрос использует символ амперсанта как обычный литерал. Когда запрос будет выполняться, будет выведен запрос для ввода значения дла переменной SID.

    select ‘Coda&Sid’ from dual;

     

    Но если вы выключите подстановку переменной, то это запрос выполнится без запроса ввода данных

     

    SET DEFINE OFF;

    select ‘Coda&Sid’ from dual;

    SET DEFINE ON;

     

    После выполнения запроса, команда SET DEFINE ON может быть использована для включения функционала подстановки переменной обратно. Если подстановка переменной выключена и амперсанд используется не как литерал, запрос вернёт ошибку.

     

    Команда VERIFY

     

    Существует два типа команд при работе с Oracle: SQL команды и команды управления окружением SQL. Команда SELECT это команда языка SQL, команда SET управляет окружением. Доступно много параметров команды SET, но для контроля подстановки переменной доступны всего две: DEFINE и VERIFY.

    Команда VERIFY управляет выводом введённого значения на экран, чтобы вы могли убедиться (verify) что подстановка осуществлена правильно. Сообщение выводится на экран в формате старого запроса, за ним идёт новый запрос с замененным значением. Команда VERIFY включает или выключает вывод на экран используя параметр OFF или ON. Если проверка выключена, то во время выполнения запроса с использованием амперсанта у вас запрашивается ввод значения, переменная заменяется, запрос выполняется и отображается результат. Если проверка включена и выполняется тот же запрос, то после ввода значения, но перед выводом результата, Oracle отображает раздел, в котором находилась переменная как старое значение с добавлением номеров строк, а затем ниже отображается новое значение с уже замененным значением.

  • Сортировка возвращаемого результата

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

     

    Предикат ORDER BY

     

    Предикат ORDER BY всегда находится в конце команды SELECT. Полный синтаксис команды SELECT будет изменяться по мере изучения возможностей команды, но ни одна директива не может быть после ORDER BY. Синтаксис SELECT с ключевым словом ORDER BY выглядит следующим образом

    SELECT *|{[DISTINCT] column|expression [alias],…}

    FROM table

    [WHERE condition(s)]

    [ORDER BY {col(s)|expr|numeric_pos} [ASC|DESC] [NULLS FIRST|LAST]];

     

    Сортировка по возрастанию или убыванию

     

    Сортировка по возрастанию более естественна для большинства типов данных и поэтому используется по умолчанию в команде ORDER BY. Сортировка по возрастанию для чисел значит от меньшего к большему, для даты – от более старой к более новой и символьные данные сортируются по в зависимости от позиции символа в алфавите. Первая часть предиката ORDER BY значит что результат может сортироваться по одному или нескольким столбцам или выражениям

    ORDER BT col(s)|expr

    Предположим что нам нужен отчёт в котором должны быть указаны фамилия сотрудника, дата приёма на работу и зарплата. Данные должны быть отсортированы по алфавиту и включать только торговых представителей и менеджеров по маркетингу. Такой запрос можно получить выполнив

     

    select last_name, hire_date, salary from employees

    where job_id in (‘SA_REP’,’MK_MAN’)

    order by last_name desc nulls last;

     

    Выбранные данные можно сортировать используя любые столбцы таблицы в секции FROM, включая столбцы которые не перечислены в списке SELECT. Добавляя ключевое слово DESC к столбцу или выражению в секции ORDER BY строки сортируются по убыванию. Параметр NULLS  LAST указывает, что если в строках результата присутствуют значения NULL то строки со значением NULL будут отображены в конце результата, после всех других отсортированных значений. Для указания сортировки таким образом чтобы значения NULL были вначале – используется ключевое слово NULL FIRST. Также данные можно сортировать основываясь на выражениях, как показано в следующем примере

     

    select last_name, salary, hire_date, sysdate-hire_date tenure

    from employees order by tenure;

     

    Наименьшее значение TENURE отображается первым в результате, так как ORDER BY указывает БД отсортировать результат используя псевдоним. Обратите внимание, что результат можно сортировать по выражению без псевдонима, но использование псевдонима делает запрос более читабельным.

    По умолчанию используются следующие параметры ORDER BY.  Самым важным является то, что если явно не задать режим DESC  — предполагается сортировка по возрастанию. Если в результате есть значения NULL то по умолчанию используется NULLS LAST при сортировке ASC и NULLS FIRST при сортировке DESC. Если не указать директиву ORDER BY в запросе, то одинаковый запрос может вернуть одинаковые данные, но в разном порядке, таким образом нельзя строить предположения о порядке возвращаемых данных без указания порядка сортировки.

     

    Сортировка по позиции

     

    В Oracle доступен альтернативный,более короткий метод указания столбца или выражения для сортировки. Вместо указания имени столбца используется его позиция в списке SELECT. Рассмотрим пример

    select last_name, hire_date, salary from employees order by 2;

     

    В ORDER BY директиве указано число 2. Это эквивалентно указанию поля HIRE_DATE, так как второй столбец в списке SELECT является столбцом HIRE_DATE. Сортировка по позиции доступна только для столбцов которые указаны в списке столбцов команды SELECT.

     

    Составная сортировка

     

    Результат может быть отсортирован по нескольким столбцам используя составную сортировку. Несколько столбцов могут быть указаны (неважно по имени или по позиции) как составной ключ сортировки, путём перечисления их в секции ORDER BY через запятую. Для выборки JOB_ID, LAST_NAME, SALARY и HIRE_DATE из таблицы EMPLOYEES и сортировки данных по убыванию в зависимости от значения столбца JO_ID, затем по возрастанию по LAST_NAME и наконец по убыванию зарплаты можно выполнить запрос такого вида

     

    select job_id, last_name, salary, hire_date from employees

    where job_id in (‘SA_REP’,’MK_MAN’) order by job_id desc nulls last, last_name, 3 desc;

  • Ограничение строк возвращаемых результатом

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

     

    Предикат WHERE

     

    Предикат WHERE расширяет команду SELECT предоставляя возможность ограничить строки результата наложением одного или нескольких условий. Запрос к таблице используя только предикаты SELECT и FROM приводит к тому, что все строки хранящиеся в таблице будут возвращены в результате выполнения запроса. Использование ключевого слова DISTINCT позволяет убрать дубликаты и результат выполнения запроса ограничивается в какой-то мере. Но что если нам нужна из таблицы только определённая информация, например, только те данные которые содержат определённое значение в конкретном столбец? Как нам получить данные только тех стран которые находятся в Европе из таблицы COUNTRIES? Или как получить только сотрудников работающих торговыми представителями? Все эти запросы можно выполнить используя предикат WHERE для указания какие конкретные строки мы хотим получить. Синтаксис команды SELECT с предикатом WHERE выглядит следующим образом

     

    SELECT *|{[DISTINCT] column|expression [alias],…}

    FROM table

    [WHERE condition(s)];

     

    Предикат WHERE всегда находится после предиката FROM. Квадратные скобки указывает на то что использование WHERE необязательно. Одно или несколько условий могут применяться для ограничения результата. Условия определяется оператором сравнения и двумя операндами. Операндами могут быть значения столбцов, литераты или выражения. Оператор равенства (equality) наиболее часто используемые оператор для ограничения результата. Пример использования предиката WHERE

     

    select country_name

    from countries

    where region_id=3;

     

    Этот пример проецирует столбец COUNTRY_NAME из таблицы COUNTRIES. Вместо выбора всех строк из таблицы предикат WHERE ограничивает результат только теми строками у которые значение столбца REGION_ID равно трём.

     

    Условия для числовых данных

     

    Условия должны быть сформулированы в зависимости от типа данных. Условия для численных значений можно устанавливать несколькими способами. Рассмотрим столбец SALARY в таблице EMPLOYEES. Тип данных столбца NUMBER(8,2). Ограничить строки по значению этого столбца можно следующим способом

     

    select last_name, salary from employees where salary = 10000;

     

    Этот запрос на фамилию и запрлату сотрудников кто зарабатывает больше 10000 выполнится успешно так как типы данных обоих операндов совпадают и совместимы. Столбец с численным типом данных также можно сравнить с другим численным столбцом той же строки в условии WHERE

     

    select last_name, salary from employees where salary = department_id;

     

    В этом примере условие WHERE никогда не выполнится так как значение зарплаты находится в диапазоне от 2100 до 99999.99 а значение номера отдела – от 10 до 110. Так как значения не пересекаются, значит строк удовлетворяющих условию нет и запрос возвращает пустой результат.

    Условие WHERE также можно использовать для сравнения столбцов и выражений или сравнения выражения с выражением

     

    select last_name, salary from employees where salary = department_id*100;

    select last_name, salary from employees where salary/10 = department_id*10;

     

    В первом примере сравнивается значение столбца SALARY со значением DEPARTAMENT_ID умноженным на 100 для каждой строки. Во втором примере сравнивается два выражения. Обратте внимания что алгебраически два примера асболютно идентичны и поэтому у двух запросов одинаковый результат

     

    Условия для символьных данных

     

    Условия для выборки строк основанные на символьных данных определяются с помощью заключения литералов в условии в одинарные кавычки. Столбец JOB_ID в таблице EMPLOYEES имеет тип данных VARCHAR(20). Предположим что вам нужен список фамилий тех сотрудников, которые работают сейчас в должности торгового представителя. Значение должности торгового представителя равно SA_REP. Следующий запрос можно использовать для этой цели

     

    select last_name from employees where job_id=’SA_REP’;

     

    Если вы попробуете выполнить запрос без заключения значения литерала в кавычки вы получите ошибку. Надо помнить что данные чувствительны к регистру, т.е. следующие условия WHERE не эквивалентны

     

    Условие 1: where job_id=SA_REP

    Условие 2: where job_id=’Sa_Rep’

    Условие 3: where job_id=’sa_rep’

     

    Условие один приведёт к возникновению ошибки ORA-00904: «SA_REP»: invalid identifier так как значение литерала не заключено в кавычки и воспринимается как название столбца. Условия два и три синтаксически валидны, но не эквивалентны. Более того, ни одно из условий не вернёт никаких данных, так как в таблице нет строки ни со значением Sa_Rep ни со значением sa_rep.

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

     

    Условие 1: where ‘A ‘||last_name||first_name = ‘A King’

    Условие 2: where first_name||’ ‘||last_name = last_name||»||first_name

    Условие 3: where ‘SA_REP’||’King’ = job_id||last_name

    Условие 4: where job_id||last_name =’SA_REP’||’King’

     

    Условия над датами

     

    Столбцы с типом данных DATE используются для хранения данных о дате и времени. Литералы даты должны заключаться в одинарные кавычки так же как символьные данные. Когда используется в условии WHERE столбец с типом данных даты – его можно сравнивать с другим столбцом даты, литералом или выражением. Литералы конвертируются к типу данных DATE используя формат по умолчанию DD-MON-RR. Если литерал встречается в выражении использующем столбец с типом данных даты, он автоматически конвертируется в дату используя формат по умолчанию. DD обозначает день, MON – первые три буквы месяца и RR – две последние цифры года (если RR – между 50 и 99 это значит что используется предыдущий век, иначе используется текущий век). Также можно указать все четыре цифры года. Рассмотрим следующие условия

     

    Условие 1: where start_date = end_date;

    Условие 2: where start_date = ’01-JAN-2001′;

    Условие 3: where start_date = ’01-JAN-01′;

    Условие 4: where start_date = ’01-JAN-99′;

     

    Первое условия проверяет равенство двух столбцов с типом данных DATE. Результатом будут строки в которых значение START_DATE и END_DATE одинаковое. Важно помнить, что даты равны только тогда, когда равны всех их части, включая день, месяц, год, часы, минуты и секунды. В главе 10 мы обсудим тип данных дата подробнее. Пока что не обращаем внимание на часы, минуты и секунды. Во втором условии START_DATE сравнивается с литералом ’01-JAN-2001’. Указаны все четыре цифры года. Такое условие валидно. Третий запрос эквивалентен воторому, так как литерал ’01-JAN-01’ преобразуется в значение ’01-JAN-2001’. Так происходит потому что RR значение меньше 50 и используется текущий (21) век. В четвёртом условии значение 01-JAN-99 будет преобразовано в 1999 так как 99 входит в диапазон от 50 до 99 и используется предыдущий век.

    Также поддерживаются арифметические действия над датами такие как добавление и вычитание. Выражение вида END_DATE – START_DAE вернёт число – количество дней между датой начала и датой завершения, а выражением STAR_DATE+30 вернёт дату которая будет через 30 дней после даты начала.

     

    Exam tip

    Условия сравнивают два значения используя оператор сравнения. Необходимо знать тип данных операндов, так как может быть необходимо заключить значение в кавычки.

     

    Операторы сравнения

     

    Оператор равенства обычно используется для отображения концепции ограничения данных используя предикат WHERE. Но ещё доступны и некоторые другие операторы. Операторы неравенства такие как «меньше» или «больше или равно» могут использоваться для создания нестрогих равенств. Оператор BETWEEN используется для определения входит ли значение столбца в диапазон между двумя значениями. Оператор IN проверяет вхождение значения в заданный набор значений (равенство хотя бы одному значению из заданного набора). Оператор LIKE – это инструмент, позволяющий сравнивать символьные значения на основании специальных шаблонов. И последний оператор сравнения это оператор IS NULL, который позволяет проверять строки на значение NULL в столбце. Эти операторы можно комбинировать в секции WHERE.

     

    Равенство и неравенство

     

    Ограничение строк возвращаемых запросом требует создания подходящего условия WHERE. Если ограничения слишком строгие, то могут быть получены всего несколько или вообще ни одной строки. Если условия построено слишком размытым – то можно получить больше строк чем необходимо. Рассмотрев разные операторы вы сможете строить гибкие условия для получения именно тех строк что вам необходимы. Как работает проверка на равенство обычно интуитивно понятно. Такие условия создаются используя оператор равенства (=). Рассмотрим запрос

     

    select last_name, salary from employees where job_id=’SA_REP’;

     

    Столбец JOB_ID каждой строки таблицы EMPLOYEE проверяется на равенство символьному литералу SA_REP. Для символьной инфомрации, понятие равенства означает что они должны быть посимвольно идентичны учитывая регистр. Когда находится такое равенство, значения необходимых столбцов из этой строки помещаются в результат запроса. Обратите внимание на то, что хотя столбец JOB_ID используется в условии – нет никакой обязательности проецировать этот столбец в результат запроса.

    Условия неравенства расширяют возможности предиката WHERE. Проверку на вхождение в диапазон значений или в набор предопределённых значений можно сделать используя операторы равенства и неравенства, но обычно предпочтительнее использовать операторы BETWEEN и LIKE. Операторы неравенства описаны в таблице 9-3.

    1

    Операторы неравенства позволяют выполнять запросы для диапазонов. У вас может возникнуть задача вернуть строки где значение столбца больше чем другое значение. Следующий пример выбирает фамилию и зарплату сотрудников у которых зарплата больше 5000:

     

    select last_name, salary from employees where salary > 5000;

     

    Сложный оператор неравенства (который состоит больше чем из одного символа) используется в следующих условиях

    Условие 1: where salary <= 3000;

    Условие 2: where salary <> department_id;

     

    В первом условии выбираются строки в которых значение зарплаты меньше или равно 3000. В условии номер два показана одна из форма как получить оператор «не равно». При использовании этого условия будут отобраны строки в которых значение зарплаты не равно номеру департамента.

    Неравество чисел интуитивно понятно. Сравнение строк и дат не так очевидно. Строки сравниваются следующим образом: оба операнда преобразуются в числовые значения. На основании кодировки и настроек NLS, каждому символу назначается числовое значение и значения суммируются. Именно эти значения в итоге сравниваются. Рассмотрим запрос

     

    select last_name from employees where last_name<‘King’

     

    Строковый-литера Kink преобразуется в число. Предположим что используется US7 ASCII кодировка с настройками локали NLS = AMERICAN, тогда значение литерала будет равно K + i + n + g = (75+105+110+103=393). Для каждой строки из таблицы EMPLOYEES значение поля LAST_NAME преобразуется в численное значение. Если полученное значение меньше 393 – то строка будет возвращена в результате запроса.

    Сравнение на неравенство со значениями даты работает примерно как сравнение строковых значений. Oracle хранит значения типа данных дата во встроенном числовом формате, и эти значения используется при сравнении. Рассмотрим пример

     

    select last_name from employees where hire_date < ’01-JAN-2010′

     

    Этот запрос вернёт фамилии сотрудников значение HIRE_DATE которых ранее первого января 2010 года.

     

    Сравнение диапазона. Оператор BETWEEN

     

    Оператор BETWEEN проверяет входит ли значение столбца или выражение в диапазон установленный двумя граничными значениями. Значение должно быть не меньше чем нижняя граница и не больше чем верхняя граница одновременно – тогда сравнение расценивается как верное.

    Предположим что вам нужны фамилии сотрудников, зарплата у которых находится между значениями 3400 и 4000. Используя оператор BETWEEN запрос будет выглядеть так

     

    select last_name from employees where salary between 3400 and 4000;

     

    Условие в операторе BETWEEN можео переписать используя два оператора неравенства

     

    select last_name from employees where salary >=3400 and salary <=4000;

     

    Но быстрее и проще использовать оператор BETWEEN

     

    Проверка вхождения в группу. Оператор IN

     

    Оператор IN проверяет является ли проверяемый элемент членом набора значений литералов. Набор определяется перечислением значений через запятую в обрамляющих скобках. Если литералы являются символьными данными или данными типа дата, то значения должны быть в одинарных кавычках. Вы можете использовать сколько угодно значений. Рассмотрим пример

    select last_name from employees where salary in (1000,4000,6000);

     

    Значение SALARY у каждой строки сравнивается со всеми значениями указанными в скобках. Если значение равно 1000, 4000 или 6000 то строка будет включена в результат. Следующие запросы используют IN для символьных данных и данных типа дата

     

    select last_name from employees where last_name in (‘Watson’,’Garbharran’,’Ramklass’);

     

    select last_name from employees where hire_date in (’01-JAN-2008′,’01-DEC-2009′);

     

    Сравнение с шаблоном. Оператор LIKE

     

    Оператор LIKE создан для символьных данных и он предоставляет гибкий механизм для поиска символов или строк. LIKE использует два специальных символа для составления шаблона: символ процента (%) и нижнее подчеркивание (_). Знак процента используется для указания нуля или более любых символов, а нижнее подчеркивание заменяет один любой символ. Вы можете использовать следующий пример для поиска сотрудников чьё имя начинается с буквы A

     

    select first_name from employees where first_name like ‘A%’;

     

    Значение столбца FIRST_NAME сравнивается со значением в кавычках как со значением литерала. В дополнении к этому символ процента вместе с оператором LIKE рассматриваются как «значение начинается с символа A,  и затем может быть ноль или более любых символов». Специальные символы могут использоваться в любой части шаблона: в начале, в середине или в конце. Также можно использовать просто специальный символ

     

    where first_name like ‘%’

     

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

     

    where last_name like ‘King’;

    where last_name = ‘King’;

     

    Символ нижнего подчеркивания означает «обязательно один любой символ». Для поиска сотрудников, чья фамилия состоит из четырёх символов, начинается на K, имеет любой второй символ и заканчивается на ng можно выполнить следующий запрос

     

    select last_name from employees where last_name like ‘K_ng’;

     

    на рисунке 9-6 показано что оба специальных символа могут использоваться отдельно, вместе, или даже несколько раз в одном шаблоне в одном условии. Первый запрос выбирает записи где COUNTRY_NAME начинается с символа I, после которого может быть один или больше символов, один из которых обязательно a. Второй запрос ищет страны, в имени которых пятым символом должен быть символ i. Длина после пятого символа не важна, и первыми четырьмя символами могут быть любые символы.

    2

     

    А что если вам нужно найти литерал, который содержит специальный символ? Специальные символы как данные можно экранировать используя идентификатор ESCAPE. В следующем примере выполняется поиск JOB_ID первыми тремя символами которых должны быть “SA_”

     

    select job_id from jobs where job_id like ‘SA\_%’ escape ‘\’;

     

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

     

    select job_id from jobs where job_id like ‘SA$_%’ escape ‘$’;

     

    Знак процента обрабатывается точно также.

     

    Сравнение значения NULL с помощью оператора IS NULL

     

    Значение NULL неизбежно встречается в базах данных. И иногда втречается задача поиска только тех записей, в которых значение поля равно NULL. Оператор IS NULL возвращает только те строки где в значении столбца именно значение NULL. Проверка значения на NULL невозможна используя оператор  равенства.

    Рассмотрим запрос которые выбирает фамилии сотрудников, у которых значение COMMISION_PCT – NULL

     

    select last_name from employees where commission_pct is null;

    Булевы операторы

     

    Булевы или логические операторы позволяют использовать несколько условий в предикате WHERE команды SELECT. Это позволяет более гибко извлекать необходимые данные из БД. К примеру нам могут быть интерестны сотрудники фамилия которых начинается на J и значение COMMISSION_PCT которых больше чем десят процентов. То есть первое условие, это ограничить фамилию сотрудников использяу шаблон “J%”. И второе условие, это проверить значение COMMISION_PCT и выбрать только те записи где значение больше 10. Эти два условия можно объединить, используя логическое «И», и применить последовательно в секции WHERE. Результат выполняющий все или некоторые, или не выполняющий определённые условия может быть получен путём использования операторов AND, OR и NOT соответственно.

     

    Оператор AND

     

    Оператор AND (логическое «И») объединяет условия в одно условие и только те данные которые выполняют все условия будут включаться в результат. Если два условия указаны в WHERE и используется оператор AND, то все строки будут проверять последовательно на выполнение обоих условий. Если данные не удовлетворяют условиям или удовлетворяют только одно условие – то данные не будут влючены в результат. Сотрудники, у которых имя начинается на J и комиссия больше 10 процентов могут быть получены следующим запросом

     

    select first_name, last_name, commission_pct, hire_date from employees where first_name like ‘J%’ and commission_pct > 0.1

     

    Обратите внимание что у нас два условия, но зарезервированное слово WHERE используется только один раз. Оператор AND объединяет два условия. Для добавления дополнительных обязательных условий, просто добавьте их, и убедитесь, что они разделены оператором AND. Вы можете определять любое количество условий. Помните, что чем больше вы условий добавляете, тем более строгой будет выборка и тем менее значений будет возвращено.

     

    Оператор OR

     

    Оператор OR  (логическое ИЛИ) разделяет два условия таким образом, что для попадания в результат данные должны удовлетворять минимум одному условию. Если у вас в секции WHERE указаны два условия, разделённые оператором OR то если выполняется либо одно, либо оба условия строка будет возвращена. Если не удовлетворяется ни одно из условий – строка исключается из выдачи. Запрос для поиска сотрудников с фамилией, начинающейся с символа “B” или с комиссией больше 35% выглядит так

     

    select first_name, last_name, commission_pct, hire_date from employees where first_name like ‘B%’ or commission_pct > 0.35;

     

    Условия разделены оператором OR. Все сотрудники фамилия которых начинается с “B” буду в результате запроса, несмотря на их значение комиссии, даже если значение COMISSION_PCT это NULL. Плюс все строки в которых значение комиссии больше 35 % будут в результате (вне зависимости от первого символа их фамилии). Дополнительные условия можно добавлять используя оператор OR. Чем больше условий OR вы добавляете тем менее строгой становится выборка и тем больше строк может быть возрващено результатом.

     

     

    Оператор NOT

     

    Оператор NOT (логическое отрицание) отменяет операторы условия. То есть данные должны удовлетворять логически обратному условию для попадания в результат. Булевы операторы тогда записываются как показано в таблице 9-4

    3

     

    Оператор NOT меняет сравнение вне зависимости от оператора сравнения. Будь то оператор равенства, неравенства, вхождения в диапазон или группу и т.п.

     

    Правила приоритета

     

    Арифметические операторы, символьные операторы, операторы сравнения и логические выражения рассматривались в контексте предиката WHERE. Но как эти операторы работают друг с другом? Иерархия приоритетов показана в таблице 9-5. Операторы одинакового уровня приоритета выполняются слева направо если они встречаются вместе в выражении. Когда оператор NOT изменяет оператор LIKE, IS NULL или IN, то приоритет оператора остаётся таким же как и без NOT.

    4

    Рассмотрим запрос в котором используются разные операторы

     

    select

    last_name,salary,department_id,job_id,commission_pct

    from

    employees

    where

    (last_name like ‘%a%’ and salary > department_id * 200

    or

    job_id in (‘MK_REP’,’MK_MAN’)) and commission_pct is not null;

     

    Столбцы LAST_NAME, SALARY, DEPARTMENT_ID, JOB_ID и COMISSION_PCT проецируются из таблицы EMPLOYEES основываясь на двух условиях. Вначале проверяется условие что в фамилии есть символ “a” и сравнивается значение с номером департамента умноженным на двести. Умножение выполняется перед сравнением, так как приоритет умножения выше чем сравнения на неравенство. Затем выбираются строки где значение JOB_ID или MK_MAN или MK_REP и значение COMISSION_PCT не NULL. Для строки, чтобы быть включенной в результат этого запроса достаточно удовлетворять либо первому либо второму условию. Изменение порядка операторов меняет смысл запроса. Рассмотрим пример

     

    select

    last_name,salary,department_id,job_id,commission_pct

    from

    employees

    where

    last_name like ‘%a%’ and salary > department_id * 100 and commission_pct is not null

    or

    job_id = ‘MK_MAN’;

     

    В этом запросе два составных условия. Первое условие проверяет фамилию на наличие символа “a” плюс значение зарплаты должно быть больше чем номер департамента умноженный на сто и значение комисси должно быть указано. Второе условие требует чтобы значение JOB_ID было MK_MAN. Строка включается в результат если выполняются либо оба, либо хотя бы одно условие.

     

    Exam tip

    Булевы операторы OR и AND позволяют использовать несколько условий в предикате WHERE в то время как оператор NOT меняет оператор сравнения и может быть использован несколько раз в одном условии. Операторы равенства, неравенства, BETWEEN, IN и LIKE сравнивают два операнда в одном условии. Только один оператор сравнения используется в одном условии.

  • Выполнение простой команды SELECT

    Практические возможности команды SELECT реализованы в исполнении команды. Ключевым моментом при выполнении любых запросов является понимание синтаксиса и правил его использования. Мы рассмотрим базовый синтаксис, затем процесс выполнения и наконец выражения и операторы, постепенно увеличивая использования данных из реляционных таблиц. Рассмотрим концпецию значения NULL и подводные камни его использования. Эти вопросы рассматриваются в следующих подпунктах

    Синтаксис простой команды SELECT

    Правила которые следует соблюдать

    Выражения и операторы

    NULL – это ничего

     

    Синтаксис простой команды SELECT

     

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

     

    SELECT * | {[DISTINCT] column|expression [alias],…}

    FROM table;

     

    Ключевое слово (или зарезервированное) команды SELECT написано в верхнем регистре. Когда пишете команду, регистр ключевых слов не важен, но ключенвые слова нельзя использовать как название столбцов или имени другого объекта базы данных. SELECT, DISTINCT и FROM это ключевые слова. Команда SELECT обычно содержит два или более параметров. Два обязательных параметра это сама команда SELECT и слово FROM. Символ | используется как лоическое ИЛИ. То есть вы можете прочитать предыдущую команду как

     

    SELECT * FROM table

     

    В таком формате символ * используется для обозначения всех столбцов. SELECT * это простой способ попросить Oracle вернуть все доступные столбцы. Такой формат используется как быстрый способ вместо набора SELECT column1, column2, … columnN для выбора всех столбцов. Параметр FROM указывает какие таблицы использовать для выбора столбцов требуемых в команде SELECT. Вы можете выполнить следующий запрос для получения всех столбцов всех строк из таблицы REGIONS в схеме HR

    select * from regions;

     

    Когда выполнится это команда, результатом будет набор всех строк со всеми столбцами принадлежащие этой таблице. Использование звёздочки в команде SELECT иногда называют «слепым» запросом так как столбцы которые будут возвращены не указаны.

    Вторая форма запроса SELECT использует такую же часть FROM но другой формат SELECT

     

    SELECT {[DISTINCT] column|expression [alias],…} FROM table;

     

    Такой запрос может быть разбит на два формата

    SELECT column1 (possibly other columns or expressions) [alias optional]

    или

    SELECT DISTINCT column1 (possibly other columns or expressions) [alias optional]

     

    Алиас это альтернативное имя столбца или выражения.  Алиасы обычно используются для отображения результата в понятном пользователю виде. Они также используются для сокращения количество символов для набора когда ссылаешься на столбец или выражение.  Перечисляя столбцы в команде SELECT вы фактически проецируете конкретную выборку результата которую вы хотите получить. Следующий запрос вернёт только столбец REGION_NAME таблицы REGIONS

     

    select region_name from regions;

     

    Вас могут попросить предоставить все должности сотрудников организации за всё время. Для этого вы можете выполнить команду SELECT * FROM JOB_HISTORY. Но такой запрос вернёт вам также EMPLOYEE_ID, START_DATE и END_DATE столбцы. Запрос который возвращает только нужные столбцы JOB_ID и DEPARTMENT_ID можно написать так

     

    select job_id, department_id from job_history;

     

    Использование ключевого слова DISTINCT позволит убрать дубликаты из результата. В некоторых случаях уникальность строк необходима. Важно понимать что критерий определения уникальности для Oracle находится после слова DISTINCT. Выборка уникальных значений job_ib из таблицы job_history с помощью следующего запроса вернёт восемь уникальных должностей

     

    select distinct job_id from job_history

     

    Важно понимать что уникальность определяется комбинацией столбцов после слова DISTINCT.

     

    select distinct department_id from job_history;

    select distinct job_id,department_id from job_history;

     

    Правила которые следует соблюдать

     

    SQL достаточно строгий язык с точки зрения синтаксиса, но он остаётся достаточно простым и гибким для поддержки разных стилей программирования. В этом разделе рассмотрим несколько базовых правил управляющих SQL запросами.

     

     

     

    Верхний или нижний регистр

     

    Регист в запросах это дело вкуса разработчика. Многие предпочитают писать запросы в нижнем регистре. Также некоторые считают что ключевые слова нужно писать в верхнем регистре, но это не так. Однако стоит придерживаться одного и того же последовательного и стандартизированного формата в группе разработчиков.

    Есть только один нюанс в использовании разного регистра. Когда вы работаете со значениями литералов – регистр имеет значение. Раасмотрим столбец JOB_ID таблицы JOB_HISTORY. Этот столбец хранит строки данных в верхнем регистре: SA_REP, ST_CLERK и т.д. Когда вы пишете запрос который будет ограничиваться значениями литералов – регистр важен. Oracle рассматривает запрос к таблице JOB_HISTORY с условием St_Clerk по другому чем запрос с условием ST_CLERK.

    Метаданные об объектах БД хранятся по умолчанию в верхнем регистре в словаре данных. Если вы посмотрите данные о таблицах в схеме HR – все имена будут в верхнем регистре. Это не значит что таблица не может быть создана с именем в нижнем регистре – это можно делать. Это всего лишь общее поведение по умолчанию.

     

    Exam tip

    SQL запросы могут быть написаны с использованием любого регистра. Нужно следить за регистром когда вы работаете со значениями-литералами и алиасами. Использование в запросе JOB_ID или job_id в названии столбца вернёт одинаковый результат, но запрос на поиск значения PRESIDENT или President вернёт разный результат.

     

    Символ конца запроса

     

    Обычно используется “;” как символ конца запроса. SQL *Plus всегда требует символа конца запроса и обычно это “;”. Запросы или группы запросов часто сохраняются как файлы скрипты для будущего использования. Запросы в скриптах обычно пишутся в нескольких строках разделяемых символом перевода строки и после завершения одной команды используется “/” или  “;”. Вы можете написать команду SELECT разбить её на строки символом переноса строки, а затем после последней строки добавить новую строку в которой будет “/” и сохранить это как файл. Затем файл можно вызвать из SQL *Plus. SQL Developer не требует символа конца строки если создаётся только один запрос. Считается хорошим тоном всегда завершать ваши запросы символом конца строки. Рассмотрим два запроса в SQL *Plus:

     

    select country_name, country_id, location_id from countries;

     

    select

    city,

    location_id,

    state_province,

    country_id

    from

    locations

    ;

     

    Первый пример показывает два важных правила. Первое – запрос заканчивается “;”. Второе – весь запрос написан в одну строку. Допустимо использовать и первый и второй варинты запроса, главное чтобы все слова запроса были до символа конца запроса.

     

     

    Отступы, читаемость и good practices

     

    Рассмотрим запрос

     

    select

    city,

    location_id,

    state_province,

    country_id

    from

    locations

    /

     

    Этот запрос показывает преимущества разделения запроса на строки для улучшения читаемости кода. Oracle всё равно как написан запрос, в одну строку или в несколько, какие отступы использованы и так далее. Хорошим тоном считается разделение блоков запроса на разные строки. Когда выражения в блоке SELECT или WHERE достаточно сложные, то разбиение этих блоков на разные строки существенно улучшает читаемость запроса. Когда вы пишете запрос – обычно этот процесс итеративный. Интерпретатор SQL гораздо более полезен если вы разрабатываете сложные выражения разбивая их на строки, так как ошибки интерпретатора выглядят как “Error at line X:”. Процесс отладки станет гораздо проще.

     

    Выражения и операторы

     

    В синтаксисе простого запроса SELECT мы видели что можно использовать столбцы или выражения. Выражения – это обычно результат какой-либо операции над значениями одного (или нескольких) столбцов или выражений. Операторы которые могут использоваться в выражениях зависят от типа данных операндов. Для численных значений доступны сложение, вычитание, умножение и деление. Для строк доступно сложения (конкатенация). Сложение и вычитание доступно для типов данных даты и времени. Как и в обычной арифметике существует предопределённый порядок выполнения операторов (operator precedence) если в выражении используется больше чем один оператор. Круглые кавычки имеют самый высокий приоритет. Деление и умножение следующие в иерархии и рассчитываются до выполнения операторов сложения и вычитания, которые имеют наименьший приоритет.

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

     

    Арифметические операторы

     

    Рассмотрим таблицу JOB_HISTORY где хранится дата начала и конца назначения должности сотруднику. Для расчёта налогов или пенсии может возникнуть потребность расчёта как долго сотрудник занимал определённую должность. Эту информацию можно получить используя арифметический оператор. Рассмотрим некоторые элементы запроса и результата выполнения этого запроса показанные на рисунке 9-5.

    1

    Рисунок 9-5 – Запрос с использованием арфметического оператора

     

    В блоке SELECT перечислены пять элементов. Четыре из них это обычные столбцы таблицы JOB_HISTORY, когда пятый используя значения исходных столбцов рассчитывает сколько дней провел сотрудник в конкретной должности. Рассмотрим сотрудника с номером 176, 9 строку результата. Этот сотрудник работал как менеджер по продажам с 1 Января 2007 года по 31 Декабря 2007 года. То есть сотрудник работал в этой должности ровно один год, 2007, который состоял из 365 дней.

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

    Для улучшения читаемости, подвыражение (операция вычитания над датами) end_date-start_date выделено кавычками. Добавление единицы заставляет результат учитывать последний день.

     

    Tip

    Во время работы с SQL вы можете часто встречать две распространённые ошибки «ORA-00923: FROM keyword not found where expected» и «ORA-00942: table or view does not exist». Обычно они указаывают на ошибку в синтаксисе или пунктуации, такие как пропущенная круглая кавычка или забытый символ конца литерала при работе со строками.

     

     

     

     

    Выражения и псевдонимы столбцов

     

    На рисунке 9-5 показан новый принцип называющийся псевдонимом столбца. Обратите внимание что столбец с результатом выражения в результате выполнения запроса озаглавлен понятным названием “Days Employed”. Этот заголовок – это и есть псевдоним. Псевдоним это альтернативное имя для столбца или выражения. Если в этом выражении не использовать псевдоним, заголовок столбца будет (END_DATE-START_DATE)+1, что не очень понятно. Псевдонимы особенно полезны при работе с выражениями или суммированием и могут реализовываться несколькими способами.  Есть несколько правил при работе с псевдонимами в команде SELECT. Псевдоним “Days Employed” на рисунке 9-5 был указан путём добавления пробела после выражения и заключен в двойные кавычки. Эти кавычки обязательны по двум причинам. Во-первых, псевдоним сотоит из нескольких слов. Во-вторых, сохранение регистра псевдонима возможно только при его заключении в двойные кавычки. Если вы укажете псевдоним из двух слов разделённых пробелом без кавычек – вы получите ошибку «ORA-00923: FROM keyword not found where expected». SQL предлагает более формальный метод указания псевдонимов путём добавления ключевого слова AS между столбцом или выражением и его псевдонимом.

     

    SELECT

    EMPLOYEE_ID AS «Employee ID»,

    JOB_ID AS «Occupation»,

    START_DATE, END_DATE,

    (END_DATE-START_DATE)+1 «Days Employed»

    FROM JOB_HISTORY;

     

    Оператор для работы со строками

     

    Символ || представляет оператор конкатенации строк. Этот оператор используется для объединения строк или выражений вместе для создания более длинного выражения. Столбцы таблицы можно объединять между собой или с значением строкового-литерала для создания одного результирующего выражения.

    Оператор конкатенации достаточно гибкий для использования несколько раз и в любом месте выражения. Рассмотрим пример

     

    SELECT ‘THE ‘||REGION_NAME||’ region is on Planet Earth’ «Planetary Location» FROM REGIONS;

     

    В этом запросе строковый-литерал “The” конкатенируется со значением столбца REGION_NAME. Затем полученная строка также конкатенируется со строковым литералом “region is on Planet Earth” и всему выражению назначается псевдоним “Planetary location”.

     

    Литералы и таблица DUAL

     

    Литералы часто используются в выражениях и ссылаются на данные которые не принадлежат объектам базы данных. Конечно конкатенация существующих столбцов тоже используется, но что делать с обработкой литералов которые не зависят от данных в столбцах таблицы. Чтобы обеспечивать согласованность, Oracle придумал решение проблемы использования базы данных для вычисления выражений которым не нужны данные объектов БД. Для того чтобы база данных рассчитала выражение, должна быть выполнена синтаксически корректная команда SELECT. Что делать если вы хотите узнать сумму двух чисел? Вы можете использовать специальную таблицу с одной строкой и одним столбцом с названием DUAL.

    Вызов таблицы DUAL показан на рисунке 9-1. В таблице доступен один столбец с названием DUMMY и типом данных строка. Вы можете выполнить запрос SELECT * FROM DUAL и вам вернётся строка с одним столбцом со значением “X”. Тестирование сложных выражений в процессе разработки выполняя запросы к таблице DUAL – это эффективный метод проверки того что вычисление выражений работает как задумано. Выражения с литералами можно проверять на любой таблице, но помните что выражения будут обрабатываться для всех строк в таблице, а в таблице DUAL всего одна строка.

     

    select ‘literal ‘||’processing using the REGIONS table’ from regions;

     

    select ‘literal ‘||’processing using the DUAL table’ from dual;

     

    Первый запрос вернёт вам четыре строки, так как в таблице REGIONS четыре строки, а второй запрос вернёт одну строку.

     

    Кавычки

     

    Строковые литералы в нашим примерах были простыми выражениями иногда добавляемыми к столбцам. Такие строковые литералы заключаются в одинарные кавычки. Например

     

    select ‘I am a character literal string’ from dual;

     

    А что если литерал уже содержит символ кавычки? Рассмотрим пример

     

    select ‘Plural’s have one quote too many’ from dual;

     

    Этот запрос вернёт ошибку ORA-00923. Так как обрабатывать такие строки? Для этого доступно два способа. Первый и самый популярный это добавление дополнительной одинарной кавычки для каждого встречаемого значения кавычки в выражении. Предыдущий пример с использованием этого способа будет выглядеть так

     

    select ‘Plural»s have one quote too many’ from dual;

     

    Использование двух одинарных кавычек для обработки каждой кавычки в тексте может быть неудобным и приводить к ошибкам по мере увеличения количества таких кавычек. Oracle предоставляет способ переопределить символ начала и конца литерала с помощью оператора q. Oracle выбрала одинарную кавычку как символ начала и конца строки, но этим символом можно назначить другой символ.

    Рассмотрим оператор q. Он позволяет установить символом начала и конца строкового литерала либо одинарный символ или один из четырёх видо скобок (), {}, [], <>. Рассмотрим примеры использования оператора q

     

    SELECT q'<Plural’s can also be specified with alternate quote operators>’ «q<>» FROM DUAL;

    SELECT q'[Even square brackets’ [] can be used for Plural’s]’ «q[]» FROM DUAL;

    SELECT q’XWhat about UPPER CASE X for Plural’sX’ «qX» FROM DUAL;

     

    Синтаксис оператора q

     

    q‘delimiter character literal which may include single quotes delimiter’

     

    где delimiter может быть символ или соотвествующая скобка. В примерах выше показано использование скобок (в первом и втором запросе), и использование символа “X” как символа начала и конца строкового литерала. Обратите внимание что символ  X тоже может использоваться в значении литерала – конец строки обозначается символом “X” и одинарной кавычкой.

     

    NULL – это ничего

     

    NULL обозначает отсутствие данных. Строка в которой содержится NULL в столбце – рассматривается как строка у которой нет данного для этого столбца. Формально NULL обозначает значение, которое неизвестно или непреминимо. Если не обрабатывать специальным образом значения NULL то ваши запросы скорее всего не выполнятся или что ещё хуже, вернёт неправильный результат. В этом разделе мы рассматриваем как обрабатывать значение NULL в столбце и как значение NULL влияет на вычисление выражений.

     

    Обязательные и необязательные столбцы

     

    Таблица хранят строки данные которые разбиты на один или несколько столбцов. У этих столбцов есть названия и тип данных. Некоторые из столбцов имею ограничения на обязательность указания значения. Таким образом любая строка дожна хранить какое либо значение отличное от NULL в этих столбцах.  Когда столбец таблицы не указан как обязательный то вы рискуете встретить значение NULL для этого столбца.

     

    Tip

    Любая арифметическая операция со значением NULL всегда возвращает NULL

     

    Oracle позволяет работать со значением NULL используя специальные функции. Подробнее об этом мы поговорим в главе 10. Деление на NULL вернёт NULL, а деление на 0 приведёт к ошибке. Когда строка объединяется со значением NULL – то значение NULL игнорируется.

     

    SELECT 1+NULL FROM DUAL;

    SELECT ‘1’||NULL FROM DUAL;

     

    Внешние ключи и необязательные столбцы

     

    Модель данных иногда ведёт к проблемным ситуациям когда таблицы связаны через первичный и внешний ключ,  но столбец внешнего ключа необязателен.

    Первичный ключ таблицы DEPARTAMENTS – это столбец DEPARTMENT_ID. В таблице EMPLOYEES столбец DEPARTMENT_ID хранит ограничение внешнего ключа для связи с таблицей DEPARTAMENTS. Это значит что в таблице EMPLOYEES не может находиться запись с таким значением столбца DEPARTMENT_ID  которого нет в таблице DEPARTMENTS. Такое ограничение обусловлено выполнением третьей нормальной формы и критически важно для ограничения целостности базы данных.

    А что насчёт значений NULL? Может быть значение NULL в столбце DEPARTAMENT_ID таблицы DEPARTAMENTS? Ответ – нет. Значение первичного ключа всегда должно быть указано. А значение в таблице EMPLOYEES? Это спорный вопрос, так как для обеспечения гибкости и покрытия всех возможных сценаривев, Oracle не может настаивать на том чтобы столбцы используемые для обеспечения ссылочной целостности были обязательными.

    Поэтому поле DEPARTMENT_ID в таблице EMPLOYEES необязательное и существует вероятность что в таблице будут существовать записи со значением NULL в столбце DEPARTMENT_ID. И такие записи существуют. Модель данных позвоняет сотруднику работать в каком-то отделе или не работать ни в одном отделе. Когда происходит операция объединения то абсолютно возможно что какие-то записи которые содержат NULL в значении ключа будут отсутствовать в результате. В главе 12 мы рассмотрим как работать с объединениями.

  • Демонстрационные схемы

    Мы будем использовать для примеров две схемы. Встроенную схему HR, которая представляет из себя пример приложения для управления человеческими ресурсами и схема WEBSTORE – пример приложения для обработки заказов. Схема HR может быть создана при создании базы данных либо быть создана позднее выполнив скрипты из Oracle Home.

     

    Схемы HR и WEBSTORE

     

    Схема HR состоит из семи таблиц, связанных первичными и внешними ключами. На рисунке 9-3 отображены отношения между таблицами как на диаграмме сущность-связь.

    Два из отношений на рисунке 9-3 могут быть сразу не совсем понятны. Первое, это отношение один-ко-многим таблицы EMPLOYEE к таблице EMPLOYEE. Это self-referencing внешний ключ. Это значит что много сотрудников может быть связано с одним сотрудником, и это основано на том факте что у многих сотрудников может быть один менеджер, но менеджер это также сотрудник. Эта связь реализована за счёт столбца внешнего ключа manager_id и первичного ключа employee_id.

    Вторая связь которая возможно требует дополнительного пояснения это двунаправленная  связь между DEPARTMENTS  и EMPLOYEES. Многие сотрудники могут работать в одном департаменте, и один сотрудник может быть менеджером многих департаментов.

    1

    В таблице 9-1 отображены столбцы таблиц схемы HR, используя описанную ранее нотацию для отображения первичных ключей (#), внешних ключей (\), обязательности (*) или необязательности (o) значения.

    Таблицы в схеме

    REGIONS содержит строки для георафических областей

    COUNTRIES содержит строки для каждой страны, которые могут закрепляться за регионом

    LOCATIONS содержат адреса, которые могут принадлежать стране

    DEPARTAMENTS хранит информацию об отделах, с необязательным адресом и необязательным полем менеджера (менеджер должен существовать как сотрудник)

    EMPLOYEES хранит строки для каждого сотрудника, каждому из которых должна быть назначена должность и необязательно менеджер и департамент. Менеджер в свою очередь должен быть в таблице сотрудников

    JOBS содержит информацию о должностях в компании. Много сотрудников могут иметь одинаковую должность

    JOB_HISTORY хранит информацию о предыдущих должностях сотрудника, уникально определяемую полями employee_id и start_date; сотруднику не может быть назначено несколько должностей в один момент времени. Каждая запись в истории ссылается на сотрудника с одной должностью в определённый момент и возможной принадлежности какому-либо отделу. Мы будем использовать HR схему для примеров и упражнений, так что она должна быть создана.

    2

    Схема WEBSTORE уже была создана если вы выполняли лабораторные работы. Если нет, мы определим отношения и связи и создадим схему и необходимые объекты. Схема WEBSTORE состоит из четырёх таблиц, связанных первичными и внешними ключами. На рисунке 9-4 покаданы связи между таблицами, как диаграмма сущность-связь.

    3

    Магазин управляет продуктами, покупателями и заказами в соответсвенно названных таблицах. Каждый заказ может состоять из нескольких продуктов с разным количеством – эти данные хранятся в таблице ORDER_ITEMS. Столбец order_item_id хранит номер для каждого уникального продукта в каждом заказе. Каждый заказ связан с одной или несколькими строками таблицы ORDER_ITEMS .

    Таблицы схемы WEBSTORE

    PRODUCTS хранит информацию о продуктах: описание, цена, статус и доступное количество.

    CUSTOMERS содержит информацию о покупателях

    ORDERS хранит информацию о заказах. Один покупатель может совершить много заказов. Заказ не может быть создан без существующего покупателя.

    ORDER_ITEMS хранит детальную информацию какие продукты были заказаны в каком заказе.

     

    Создание демонстрационных схем

     

    Если вы создавали БД используя лабораторное пособие то схема HR уже создана. Доступна опция создания демонстрационной схемы при создании базы с помощью DBCA.

    Если схема не была создана в момент создания БД вы можете создать её выполнив скрипт установленный в домашнюю директорию БД. Этот скрип необходимо выполнить используя SQL *Plus иди SQL Developer с правами пользователя SYSDBA. Во время выполнения будут запрошены некоторые значения. Например в среде Linux вначале запустим SQL *Plus из командной строки ОС

    root@> sqlplus / as sysdba

     

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

    Затем выполните команду в SQL *Plus

     

    SQL> @?/demo/schema/human_resources/hr_main.sql

     

    Символ “?” это переменная которую SQL *Plus заменит на путь к домашней директории Oracle. Выведется запрос на пароль пользователя HR, табличное и временное пространство, пароль аккаунта SYS и путь куда записывать лог о выполнении скрипта. Обычно значения табличного пространства по умолчанию и временного пространтсва это USERS и TEMP, но они должны быть созданы перед запуском скрипта. После выполнения скрипта вы будете подключены к БД как пользователь HR. Чтобы убедиться в этом выполните команду

     

    SQL> show user

     

    Вы увидите что подключен аккаунт HR; затем выполните

     

    select table_name from user_tables;

     

    И вы увидите семть таблиц схемы HR.

    Для создания схемы WEBSTORE (если она не создана в процессе выполнения лабораторных работ) выполните следующие запросы для создания необходимых объектов и добавления данных которые будут использоваться далее.

     

    root@> sqlplus / as sysdba

     

    SQL> create user webstore identified by oracle default tablespace users temporary tablespace temp quota unlimited on users;

    SQL> grant create session, create table, create sequence to webstore;

    SQL> ALTER SYSTEM SET DEFERRED_SEGMENT_CREATION=FALSE;

     

    SQL> connect webstore/oracle

     

    SQL> create table customers(

    customer_id number(8) not null constraint pk_customer_id primary key,

    join_date date default sysdate not null,

    customer_status varchar2(8) not null, customer_name varchar2(20) not null,

    creditrating varchar2(10) not null, email varchar2(50) not null);

     

    SQL> create table products(

    product_id number(8) not null constraint pk_product_id primary key,

    product_description varchar2(20) not null,

    product_status varchar2(8) not null, price number(10,2) not null,

    price_date date not null, stock_count number(8) not null);

     

    SQL> create table orders(

    order_id number(8) not null constraint pk_order_id primary key,

    order_date date not null, order_status varchar2(8) not null,

    order_amount number(10,2) not null,

    customer_id number(8) constraint fk_customer_id references customers (customer_id));

     

    SQL> create table order_items(

    order_item_id number(8) not null,

    order_id number(8) constraint fk_order_id references orders(order_id),

    product_id number(8) constraint fk_prod_id references products(product_id),

    quantity number);

     

    SQL> create sequence cust_seq;

    SQL> create sequence order_seq;

    SQL> create sequence prod_seq;

     

    После того как объекты созданы используйте следующие запросы которые запросят ввод данных для добавления строк в таблице, основываясь на данных в таблице 9-2.

     

    insert into customers (customer_id, customer_status, customer_name, creditrating, email)

    values (cust_seq.nextval, ‘&cust_status’, ‘&cust_name’, ‘&creditrating’, ‘&email’);

     

    insert into products(product_id, product_description, product_status, price, price_date, stock_count)

    values (prod_seq.nextval, ‘&product_description’, ‘ACTIVE’, &price, sysdate, &stock_count);

     

    insert into orders(order_id, order_date, order_status, order_amount, customer_id)

    values (order_seq.nextval, sysdate, ‘&order_status’, &order_amount, &customer_id);

     

    insert into order_items values (&item_id, &order_id, &product_id, &quantity);

    commit;

    4