alan_beaulieu-learning_sql-ru (865932), страница 11
Текст из файла (страница 11)
Поэтому, чтобы полностью понять роль блока select, надо немного разобраться с блоком from. Вот запрос для начала:mysql> SELECT *> FROM department;+++| dept_id | name|+++|1 | Operations||2 | Loans||3 | Administration |+++3 rows in set (0.04 sec)В данном запросе в блоке from указана всего одна таблица (department),и блок select показывает, что в результирующий набор должны бытьвключены все столбцы (обозначено символом «*») таблицы department. Этот запрос можно перевести на естественный язык следующимобразом:Покажи мне все столбцы таблицы department.Выбрать все столбцы можно не только с помощью символа звездочки,но и явно указав имена интересующих столбцов:mysql> SELECT dept_id, name> FROM department;+++| dept_id | name|+++|1 | Operations||2 | Loans||3 | Administration |+++3 rows in set (0.01 sec)Результаты аналогичны первому запросу, поскольку в блоке selectуказаны все столбцы таблицы department (dept_id и name).
А можно выбрать только некоторые из столбцов таблицы department:mysql> SELECT name> FROM department;Блок select55++| name|++| Operations|| Loans|| Administration |++3 rows in set (0.00 sec)Таким образом, задача блока select заключается в следующем:Блок select определяет, какие из всех возможных столбцов должны бытьвключены в результирующий набор запроса.Если бы приходилось выбирать столбцы только из таблицы или таблиц, указанных в блоке from, было бы скучновато.
Хорошо, что можнодобавить остроты, включив в блок select такие вещи, как:• Литералы, например числа или строки• Выражения, например transaction.amount * 1• Вызовы встроенных функций, например ROUND(transaction.amount, 2)Следующий запрос демонстрирует использование столбца таблицы, литерала, выражения и вызова встроенной функции в одном запросе к таблице employee:mysql> SELECT emp_id,> 'ACTIVE',> emp_id * 3.14159,> UPPER(lname)> FROM employee;+++++| emp_id | ACTIVE | emp_id * 3.14159 | UPPER(lname) |+++++|1 | ACTIVE |3.14159 | SMITH||2 | ACTIVE |6.28318 | BARKER||3 | ACTIVE |9.42477 | TYLER||4 | ACTIVE |12.56636 | HAWTHORNE||5 | ACTIVE |15.70795 | GOODING||6 | ACTIVE |18.84954 | FLEMING||7 | ACTIVE |21.99113 | TUCKER||8 | ACTIVE |25.13272 | PARKER||9 | ACTIVE |28.27431 | GROSSMAN||10 | ACTIVE |31.41590 | ROBERTS||11 | ACTIVE |34.55749 | ZIEGLER||12 | ACTIVE |37.69908 | JAMESON||13 | ACTIVE |40.84067 | BLAKE||14 | ACTIVE |43.98226 | MASON||15 | ACTIVE |47.12385 | PORTMAN||16 | ACTIVE |50.26544 | MARKHAM||17 | ACTIVE |53.40703 | FOWLER||18 | ACTIVE |56.54862 | TULMAN|56Глава 3.
Азбука запросов+++++18 rows in set (0.05 sec)Выражения и встроенные функции будут подробно рассмотрены позже,но я хотел дать представление о том, что может быть включено в блокselect. Если требуется только выполнить встроенную функцию или вычислить простое выражение, можно вообще обойтись без блока from.Вот пример:mysql> SELECT VERSION( ),> USER( ),> DATABASE( );++++| VERSION() | USER()| DATABASE( )|++++| 4.1.11nt | lrngsql@localhost | bank|++++1 row in set (0.02 sec)Поскольку данный запрос просто вызывает три встроенные функциии не извлекает данные из таблиц, блок from здесь не нужен.Псевдонимы столбцовХотя инструмент mysql и генерирует имена для столбцов, возвращаемых в результате запроса, вы можете задавать эти имена самостоятельно. Кроме того, что при желании можно дать другое имя столбцуиз таблицы (если у него «плохое» или неоднозначное имя), практически наверняка вы захотите посвоему назвать те столбцы результирующего набора, которые будут сформированы в результате выполнениявыражения или встроенной функции.
Сделать это можно добавлениемпсевдонима столбца после каждого элемента блока select. Вот предыдущий запрос к таблице employee, в котором для трех столбцов указаныпсевдонимы:mysql> SELECT emp_id,> 'ACTIVE' status,> emp_id * 3.14159 empid_x_pi,> UPPER(lname) last_name_upper> FROM employee;+++++| emp_id | status | empid_x_pi | last_name_upper |+++++|1 | ACTIVE |3.14159 | SMITH||2 | ACTIVE |6.28318 | BARKER||3 | ACTIVE |9.42477 | TYLER||4 | ACTIVE | 12.56636 | HAWTHORNE||5 | ACTIVE | 15.70795 | GOODING||6 | ACTIVE | 18.84954 | FLEMING||7 | ACTIVE | 21.99113 | TUCKER||8 | ACTIVE | 25.13272 | PARKER|Блок select57|9 | ACTIVE | 28.27431 | GROSSMAN||10 | ACTIVE | 31.41590 | ROBERTS||11 | ACTIVE | 34.55749 | ZIEGLER||12 | ACTIVE | 37.69908 | JAMESON||13 | ACTIVE | 40.84067 | BLAKE||14 | ACTIVE | 43.98226 | MASON||15 | ACTIVE | 47.12385 | PORTMAN||16 | ACTIVE | 50.26544 | MARKHAM||17 | ACTIVE | 53.40703 | FOWLER||18 | ACTIVE | 56.54862 | TULMAN|+++++18 rows in set (0.00 sec)Как видно из заголовков столбцов, второй, третий и четвертый столбцы теперь имеют осмысленные имена, а не обозначены просто функцией или выражением, сформировавшим этот столбец.
Если посмотретьна блок select, можно увидеть, что псевдонимы status, empid_x_pi и last_name_upper добавлены после второго, третьего и четвертого столбцов.Думаю, все согласятся с тем, что с присвоенными псевдонимами столбцов выходные данные стали понятнее; кроме того, с ними легче работать программно, если запросы формируются из Java или C#, а не интерактивно посредством инструмента командной строки mysql.Уничтожение дубликатовВ некоторых случаях запрос может возвратить дублирующие строкиданных.
Например, при выборе ID всех клиентов, имеющих счета, было бы представлено следующее:mysql> SELECT cust_id> FROM account;++| cust_id |++|1 ||1 ||1 ||2 ||2 ||3 ||3 ||4 ||4 ||4 ||5 ||6 ||6 ||7 ||8 ||8 ||9 |58Глава 3. Азбука запросов|9 ||9 ||10 ||10 ||11 ||12 ||13 |++24 rows in set (0.00 sec)Поскольку у некоторых клиентов по нескольку счетов, один и тот жеID клиента будет выведен столько раз, сколько счетов имеет клиент.Но, очевидно, целью данного запроса является выбор клиентов, имеющих счета, а не получение ID клиента для каждой строки таблицы account. Добиться этого можно, поместив ключевое слово distinct (отличный) непосредственно после ключевого слова select, как в следующем примере:mysql> SELECT DISTINCT cust_id> FROM account;++| cust_id |++|1 ||2 ||3 ||4 ||5 ||6 ||7 ||8 ||9 ||10 ||11 ||12 ||13 |++13 rows in set (0.01 sec)Теперь в результирующем наборе 13 строк, по одной для каждого клиента, а не 24 строки, по одной для каждого счета.Если не требуется, чтобы сервер удалял дублирующие данные, или выуверены, что в результирующем наборе их не будет, вместо DISTINCTможно указать ключевое слово ALL (все).
Однако ключевое слово ALLприменяется по умолчанию и в явном указании не нуждается, поэтомубольшинство программистов не включает ALL в запросы.Запомните, что формирование набора уникальных значенийтребует сортировки данных, что в случае больших результирующих наборов может занять много времени. Не поддавайтесь59Блок fromсоблазну использовать DISTINCT только для того, чтобы гарантировать отсутствие дублирования; лучше потратьте некотороевремя на осмысление данных, с которыми работаете, чтобы уженаверняка знать, где дублирование возможно.Блок fromДо сих пор мы рассматривали запросы, в блоках from которых былауказана только одна таблица.
Хотя большинство книг по SQL определяют блок from просто как список из одной или более таблиц, мне быхотелось расширить это определение следующим образом:Блок from определяет таблицы, используемые запросом, а также средствасвязывания таблиц.Это определение включает две разные, но взаимосвязанные концепции, которые будут изучены в следующих разделах.ТаблицыПри встрече с термином table большинство людей представляют себенабор взаимосвязанных строк, хранящихся в базе данных. Хотя одиниз типов таблиц действительно описывается именно так, мне бы хотелось использовать это слово в более общем значении – избавиться отлюбого упоминания о способах хранения данных, сосредоточившисьтолько на наборе взаимосвязанных строк.
Этому свободному определению соответствуют три разных типа таблиц:•Постоянные таблицы (т. е. созданные с помощью выражения createtable)•Временные таблицы (т. е. строки, возвращенные подзапросом)•Виртуальные таблицы (представления) (т. е. созданные с помощьювыражения create view)Каждый из этих типов таблиц может быть включен в блок from запроса. На данный момент вы уже вполне освоили включение постоянныхтаблиц, поэтому далее кратко описаны другие типы таблиц, которыемогут использоваться в блоке from.Таблицы, формируемые подзапросомПодзапрос (subquery) – это запрос, содержащийся в другом запросе.Подзапросы заключаются в круглые скобки и могут располагатьсяв различных частях выражения select.
Однако в рамках блока from подзапрос выполняет функцию формирования временной таблицы, видимой для всех остальных блоков запроса и способной взаимодействоватьс другими таблицами, указанными в блоке from. Вот простой пример:mysql> SELECT e.emp_id, e.fname, e.lname> FROM (SELECT emp_id, fname, lname, start_date, title60Глава 3. Азбука запросов> FROM employee) e;++++| emp_id | fname| lname|++++|1 | Michael | Smith||2 | Susan| Barker||3 | Robert | Tyler||4 | Susan| Hawthorne ||5 | John| Gooding ||6 | Helen| Fleming ||7 | Chris| Tucker||8 | Sarah| Parker||9 | Jane| Grossman ||10 | Paula| Roberts ||11 | Thomas | Ziegler ||12 | Samantha | Jameson ||13 | John| Blake||14 | Cindy| Mason||15 | Frank| Portman ||16 | Theresa | Markham ||17 | Beth| Fowler||18 | Rick| Tulman|++++18 rows in set (0.00 sec)Здесь подзапрос к таблице employee возвращает пять столбцов, а основной запрос (containing query) ссылается на три из пяти доступных столбцов.
Запрос ссылается на подзапрос посредством псевдонима, в данномслучае e. Это упрощенный, практически бесполезный пример подзапроса в блоке from; подробный рассказ о подзапросах можно найтив главе 9.ПредставленияПредставление (view) – это запрос, хранящийся в словаре данных (datadictionary). Оно выглядит и работает как таблица, но с представлением не ассоциированы никакие данные (вот почему я называю это виртуальной таблицей). При выполнении запроса к представлению запрос соединяется с описанием представления и создается окончательный запрос, который и будет выполнен.Чтобы продемонстрировать это, приведу описание представления, запрашивающего таблицу employee и включающего вызов встроеннойфункции:CREATE VIEW employee_vw ASSELECT emp_id, fname, lname,YEAR(start_date) start_yearFROM employee;После создания представления никакие дополнительные данные не создаются: сервер просто сохраняет выражение select для дальнейшего61Блок fromиспользования.
Теперь, когда представление существует, можно делать запросы к нему:SELECT emp_id, start_yearFROM employee_vw;Emp_id start_year 120012200232000420025200362004720048200292002102002112000122003132000142002152003162001172002182002Представления создаются по разным причинам, в том числе с цельюскрыть столбцы от пользователей и упростить сложно устроенные БД.MySQL до версии 5.0.1 не поддерживает представления. Однакоони широко используются другими серверами БД, поэтому тот,кто планирует работать с MySQL, должен помнить о них.Поскольку MySQL версии 4.1.11 не включает представления,в предыдущем запросе намеренно не показано приглашениеmysql> и обычное форматирование результирующего набора.Этот же прием применяется в других главах книги при описании возможности SQL, еще не реализованной в MySQL.Связи таблицВторое отступление от определения простого блока from: если в блокеfrom присутствует более одной таблицы, обязательно должны бытьвключены и условия, используемые для связывания (link) таблиц.