Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
11
Добавлен:
15.01.2021
Размер:
10.35 Mб
Скачать

Пример 4: использование функции COUNT в запросе с условием

Решение 2.1.4.b{29}.

Здесь мы расширяем решение{29} задачи 2.1.4.a{29}, добавляя ключевое слово DISTINCT в параметр функции COUNT, что обеспечивает подсчёт неповторяющихся

значений поля sb_book.

MySQL

Решение 2.1.4.b

1

SELECT

COUNT(DISTINCT `sb_book`) AS `in_use`

2

FROM

`subscriptions`

3

WHERE

`sb_is_active` = 'Y'

 

 

MS SQL

Решение 2.1.4.b

1

SELECT

COUNT(DISTINCT [sb_book]) AS [in_use]

2

FROM

[subscriptions]

3

WHERE

[sb_is_active] = 'Y'

 

 

 

Oracle

 

Решение 2.1.4.b

1

SELECT

COUNT(DISTINCT "sb_book") AS "in_use"

2

FROM

"subscriptions"

3

WHERE

"sb_is_active" = 'Y'

Задание 2.1.4.TSK.A: показать, сколько всего раз читателям выдавались книги.

Задание 2.1.4.TSK.B: показать, сколько читателей брало книги в библиотеке.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 30/545

Пример 5: использование функций SUM, MIN, MAX, AVG

2.1.5. Пример 5: использование функций SUM, MIN, MAX, AVG

Задача 2.1.5.a{31}: показать общее (сумму), минимальное, максимальное и среднее значение количества экземпляров книг в библиотеке.

Ожидаемый результат 2.1.5.a.

sum

min

max

avg

33

1

12

4.7143

Решение 2.1.5.a{31}.

В такой простой формулировке эта задача решается запросом, в котором достаточно перечислить соответствующие функции, передав им в качестве параметра поле b_quantity (и только в MS SQL Server придётся сделать небольшую доработку).

MySQL Решение 2.1.5.a

1SELECT SUM(`b_quantity`) AS `sum`,

2MIN(`b_quantity`) AS `min`,

3MAX(`b_quantity`) AS `max`,

4AVG(`b_quantity`) AS `avg`

5 FROM `books`

MS SQL Решение 2.1.5.a

1SELECT SUM([b_quantity]) AS [sum],

2MIN([b_quantity]) AS [min],

3MAX([b_quantity]) AS [max],

4AVG(CAST([b_quantity] AS FLOAT)) AS [avg]

5 FROM [books]

Oracle Решение 2.1.5.a

1SELECT SUM("b_quantity") AS "sum",

2MIN("b_quantity") AS "min",

3MAX("b_quantity") AS "max",

4AVG("b_quantity") AS "avg"

5FROM "books"

Обратите внимание на 4-ю строку в запросе 2.1.5.a для MS SQL Server: без приведения функцией CAST значения количества книг к дроби, итоговый результат работы функции AVG будет некорректным (это будет целое число), т.к. MS SQL Server выбирает тип данных результата на основе типа данных входного параметра. Продемонстрируем это.

MS SQL Решение 2.1.5.a (пример запроса с ошибкой)

1SELECT SUM([b_quantity]) AS [sum],

2MIN([b_quantity]) AS [min],

3MAX([b_quantity]) AS [max],

4AVG([b_quantity]) AS [avg]

5FROM [books]

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 31/545

Пример 5: использование функций SUM, MIN, MAX, AVG

Получится:

sum

min

max

avg

 

33

1

12

4

 

 

А должно быть:

 

 

 

 

sum

min

max

avg

33

1

12

4.7143

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

Исследование 2.1.5.EXP.A: рассмотрим реакцию различных СУБД на ситуацию переполнения разрядной сетки.

Создадим в БД «Исследование» таблицу overflow с одним числовым целочисленным полем:

dm MySQL

dm SQLServ er2012

dm Oracle

ov erflow

ov erflow

ov erflow

«column»

«column»

«column»

x: INT

x: int

x: NUMBER(10)

MySQL MS SQL Server Oracle

Рисунок 2.1.g — Таблица overflow во всех трёх СУБД

Поместим в созданную таблицу три максимальных значения для её поля x:

x

 

x

 

x

2147483647

 

2147483647

 

9999999999

2147483647

 

2147483647

 

9999999999

2147483647

 

2147483647

 

9999999999

MySQL

MS SQL Server

Oracle

Теперь выполним для каждой СУБД запросы на получение суммы значений из поля x и среднего значения в поле x:

MySQL Исследование 2.1.5.EXP.A

1-- Запрос 1: SUM

2SELECT SUM(`x`) AS `sum`

3 FROM `overflow`

1-- Запрос 2: AVG

2SELECT AVG(`x`) AS `avg`

3FROM `overflow`

MS SQL Исследование 2.1.5.EXP.A

1-- Запрос 1: SUM

2SELECT SUM([x]) AS [sum]

3 FROM [overflow]

1-- Запрос 2: AVG

2SELECT AVG([x]) AS [avg]

3FROM [overflow]

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 32/545

Пример 5: использование функций SUM, MIN, MAX, AVG

Oracle Исследование 2.1.5.EXP.A

1-- Запрос 1: SUM

2SELECT SUM("x") AS "sum"

3 FROM "overflow"

1-- Запрос 2: AVG

2SELECT AVG("x") AS "avg"

3FROM "overflow"

MySQL и Oracle выполнят запросы 2.1.5.EXP.A и вернут корректные данные, а в MS SQL Server мы получим сообщение об ошибке:

Msg 8115, Level 16, State 2, Line 1. Arithmetic overflow error converting expression to data type int.

Это вполне логично, т.к. при попытке разместить в переменной типа INT трёхкратное максимальное значение типа INT, возникает переполнение разрядной сетки.

MySQL и Oracle менее подвержены этому эффекту, т.к. у них «в запасе» есть DECIMAL и NUMBER, в формате которых и происходит вычисление. Но при достаточном объёме данных там тоже возникает переполнение разрядной сетки.

Особая опасность этой ошибки состоит в том, что на стадии разработки и поверхностного тестирования БД она не проявляется, и лишь со временем, когда у реальных пользователей накопится большой объём данных, в какой-то момент ранее прекрасно работавшие запросы перестают работать.

Исследование 2.1.5.EXP.B. Чтобы больше не возвращаться к особенностям работы агрегирующих функций, рассмотрим их поведение в случае наличия в анализируемом поле NULL-значений, а также в случае пустого набора входных значений.

Используем ранее созданную таблицу table_with_nulls{26}. В ней по-преж- нему находятся следующие данные:

x

1

1

2

NULL

Выполним запросы 2.1.5.EXP.B:

MySQL Исследование 2.1.5.EXP.B

1SELECT SUM(`x`) AS `sum`,

2MIN(`x`) AS `min`,

3MAX(`x`) AS `max`,

4AVG(`x`) AS `avg`

5 FROM `table_with_nulls`

MS SQL Исследование 2.1.5.EXP.B

1SELECT SUM([x]) AS [sum],

2MIN([x]) AS [min],

3MAX([x]) AS [max],

4AVG(CAST([x] AS FLOAT)) AS [avg]

5 FROM [table_with_nulls]

Oracle Исследование 2.1.5.EXP.B

1SELECT SUM("x") AS "sum",

2MIN("x") AS "min",

3MAX("x") AS "max",

4AVG("x") AS "avg"

5FROM "table_with_nulls"

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 33/545

Пример 5: использование функций SUM, MIN, MAX, AVG

Все запросы 2.1.5.EXP.B возвращают почти одинаковый результат (разница только в количестве знаков после запятой в значении функции AVG: у MySQL там четыре знака, у MS SQL Server и Oracle — 14 и 38 знаков соответственно):

sum

min

max

avg

4

1

2

1.3333

Как легко заметить из полученных данных, ни одна из функций не учитывает NULL-значения.

Исследование 2.1.5.EXP.C. Последний эксперимент будет заключаться в применении к выборке такого условия, которому не соответствует ни один ряд: таким образом в выборке окажется пустое множество строк.

MySQL Исследование 2.1.5.EXP.C

1SELECT SUM(`x`) AS `sum`,

2MIN(`x`) AS `min`,

3MAX(`x`) AS `max`,

4AVG(`x`) AS `avg`

5

 

FROM

`table_with_nulls`

6

 

WHERE

`x` < 0

 

 

 

 

MS SQL Исследование 2.1.5.EXP.C

1SELECT SUM([x]) AS [sum],

2MIN([x]) AS [min],

3MAX([x]) AS [max],

4AVG(CAST([x] AS FLOAT)) AS [avg]

 

5

 

FROM

[table_with_nulls]

 

6

 

WHERE

[x] < 0

 

 

 

 

 

Oracle

 

Исследование 2.1.5.EXP.C

1SELECT SUM("x") AS "sum",

2MIN("x") AS "min",

3MAX("x") AS "max",

4AVG("x") AS "avg"

5

 

FROM

"table_with_nulls"

6

 

WHERE

"x" < 0

Здесь все три СУБД также работают одинаково, наглядно демонстрируя, что на пустом множестве функции SUM, MIN, MAX, AVG возвращают NULL:

sum

min

max

avg

NULL

NULL

NULL

NULL

Также обратите внимание, что при вычислении среднего значения не произошло ошибки деления на ноль.

Логику работы на пустом множестве значений функции COUNT мы уже рассмотрели ранее (см. исследование 2.1.3.EXP.B{28}).

Задание 2.1.5.TSK.A: показать первую и последнюю даты выдачи книги читателю.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 34/545

Пример 6: упорядочивание выборки

2.1.6. Пример 6: упорядочивание выборки

Задача 2.1.6.a{35}: показать все книги в библиотеке в порядке возрастания их года издания.

Задача 2.1.6.b{36}: показать все книги в библиотеке в порядке убывания их года издания.

Ожидаемый результат 2.1.6.a.

b_name

b_year

Курс теоретической физики

1981

Евгений Онегин

1985

Сказка о рыбаке и рыбке

1990

Искусство программирования

1993

Язык программирования С++

1996

Психология программирования

1998

Основание и империя

2000

Ожидаемый результат 2.1.6.b.

b_name

b_year

Основание и империя

2000

Психология программирования

1998

Язык программирования С++

1996

Искусство программирования

1993

Сказка о рыбаке и рыбке

1990

Евгений Онегин

1985

Курс теоретической физики

1981

Решение 2.1.6.a{35}.

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

поле, по которому производится сортировка (b_year)

направление сортировки (ASC).

MySQL Решение 2.1.6.a

1SELECT `b_name`,

2`b_year`

3

 

FROM

`books`

 

 

 

 

4

 

ORDER

BY `b_year` ASC

MS SQL Решение 2.1.6.a

1SELECT [b_name],

2[b_year]

3

 

FROM

[books]

4

 

ORDER

BY [b_year] ASC

 

 

 

 

1 В повседневной жизни всё равно большинство людей использует тут термин «сортировка» вместо «упорядочивание», но это не совсем идентичные понятия. «Сортировка» больше относится к процессу изменения порядка, а «упорядочивание» к готовому результату.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 35/545

Пример 6: упорядочивание выборки

Oracle Решение 2.1.6.a

1SELECT "b_name",

2"b_year"

3

 

FROM

"books"

4

 

ORDER

BY "b_year" ASC

Решение 2.1.6.b{35}.

Здесь (в отличие от решения{35} задачи 2.1.6.a{35}) всего лишь необходимо поменять направление сортировки с «по возрастанию» (ASC) на «по убыванию»

(DESC).

MySQL Решение 2.1.6.b

1SELECT `b_name`,

2`b_year`

3

 

FROM

`books`

4

 

ORDER

BY `b_year` DESC

 

 

 

 

MS SQL Решение 2.1.6.b

1SELECT [b_name],

2[b_year]

3

 

FROM

[books]

4

 

ORDER

BY [b_year] DESC

Oracle Решение 2.1.6.b

1SELECT "b_name",

2"b_year"

3

 

FROM

"books"

4

 

ORDER

BY "b_year" DESC

Альтернативное решение можно получить добавлением знака «минус» перед именем поля, по которому сортировка реализована по возрастанию, т.е. ORDER

BY числовое_поле DESC эквивалентно ORDER BY -числовое_поле ASC.

MySQL Решение 2.1.6.b (альтернативный вариант)

1SELECT `b_name`,

2`b_year`

3

 

FROM

`books`

4

 

ORDER

BY -`b_year` ASC

 

 

 

 

MS SQL Решение 2.1.6.b (альтернативный вариант)

1SELECT [b_name],

2[b_year]

3

 

FROM

[books]

4

 

ORDER

BY -[b_year] ASC

Oracle Решение 2.1.6.b (альтернативный вариант)

1SELECT "b_name",

2"b_year"

3

 

FROM

"books"

4

 

ORDER

BY -"b_year" ASC

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 36/545

Пример 6: упорядочивание выборки

Исследование 2.1.6.EXP.A. Ещё одна неожиданная проблема с упорядочиванием связана с тем, где различные СУБД по умолчанию располагают NULL-значения — в начале выборки или в конце. Проверим.

Снова воспользуемся готовой таблицей table_with_nulls{26}. В ней попрежнему находятся следующие данные:

x

1

1

2

NULL

Выполним запросы 2.1.6.EXP.A:

MySQL

Исследование 2.1.6.EXP.A

1

SELECT

`x`

2

FROM

`table_with_nulls`

3

ORDER

BY `x` DESC

 

 

MS SQL

Исследование 2.1.6.EXP.A

1

SELECT

[x]

2

FROM

[table_with_nulls]

3

ORDER

BY [x] DESC

 

 

 

Oracle

 

Исследование 2.1.6.EXP.A

1

SELECT

"x"

2

FROM

"table_with_nulls"

3

ORDER

BY "x" DESC

Результаты будут следующими (обратите внимание на то, где расположено NULL-значение):

x

 

x

 

x

2

 

2

 

NULL

1

 

1

 

2

1

 

1

 

1

NULL

 

NULL

 

1

MySQL

MS SQL Server

Oracle

Получить в MySQL и MS SQL Server поведение, аналогичное поведению Oracle (и наоборот), можно с использованием следующих запросов:

MySQL

Исследование 2.1.6.EXP.A

1

SELECT

`x`

2

FROM

`table_with_nulls`

3

ORDER

BY `x` IS NULL DESC,

4

 

 

`x` DESC

 

 

MS SQL

Исследование 2.1.6.EXP.A

1

SELECT

[x]

2

FROM

[table_with_nulls]

3

ORDER

BY ( CASE

4

 

 

WHEN [x] IS NULL THEN 0

5

 

 

ELSE 1

6

 

 

END ) ASC,

7

 

 

[x] DESC

 

 

 

Oracle

 

Исследование 2.1.6.EXP.A

1

SELECT

"x"

2

FROM

"table_with_nulls"

3

ORDER

BY "x" DESC NULLS LAST

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 37/545

Пример 6: упорядочивание выборки

В случае с Oracle мы явно указываем, поместить ли NULL-значения в начало выборки (NULLS FIRST) или в конец выборки (NULLS LAST). Поскольку MySQL и MS SQL Server не поддерживают такой синтаксис, выборку приходится упорядочивать по двум уровням: первый уровень (строка 3 для MySQL, строки 3-6 для MS SQL Server) — по признаку «является ли значение поля NULL’ом», второй уровень

— по самому значению поля.

Задание 2.1.6.TSK.A: показать список авторов в обратном алфавитном порядке (т.е. «Я А».

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 38/545

Пример 7: использование составных условий

2.1.7. Пример 7: использование составных условий

Задача 2.1.7.a{39}: показать книги, изданные в период 1990-2000 годов, представленные в библиотеке в количестве трёх и более экземпляров.

Задача 2.1.7.b{40}: показать идентификаторы и даты выдачи книг за лето 2012-го года.

Ожидаемый результат 2.1.7.a.

 

b_name

b_year

b_quantity

Сказка о рыбаке и рыбке

1990

3

Основание и империя

2000

5

Язык программирования С++

1996

3

Искусство программирования

1993

7

 

Ожидаемый результат 2.1.7.b.

 

 

 

 

 

 

sb_id

sb_start

 

 

 

42

2012-06-11

 

 

 

57

2012-06-11

 

 

 

Решение 2.1.7.a{39}.

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

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

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

MySQL Решение 2.1.7.a

1-- Вариант 1: использование BETWEEN

2SELECT `b_name`,

3`b_year`,

4`b_quantity`

5

 

FROM

`books`

 

6

 

WHERE

`b_year` BETWEEN 1990

AND 2000

7

 

 

AND `b_quantity` >= 3

 

 

 

 

 

 

1-- Вариант 2: использование двойного неравенства

2SELECT `b_name`,

3`b_year`,

4`b_quantity`

5

 

FROM

`books`

6

 

WHERE

`b_year` >= 1990

7AND `b_year` <= 2000

8AND `b_quantity` >= 3

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 39/545