alan_beaulieu-learning_sql-ru (865932), страница 16
Текст из файла (страница 16)
Если требуется несколько более сложный поиск, можно использовать нескольковыражений поиска, как показано в следующем примере:mysql> SELECT emp_id, fname, lname> FROM employee> WHERE lname LIKE 'F%' OR lname LIKE 'G%';++++| emp_id | fname | lname|++++|5 | John | Gooding ||6 | Helen | Fleming ||9 | Jane | Grossman ||17 | Beth | Fowler |++++4 rows in set (0.00 sec)Этот запрос находит всех сотрудников, фамилия которых начинаетсяс «F» или «G».Регулярные выраженияЕсли символы маски не обеспечивают достаточной гибкости, для построения выражений поиска можно использовать регулярные выражения. По существу, регулярные выражения – это мощнейшие выражения поиска. Регулярные выражения хорошо знакомы разработчикам на таких языках программирования, как Perl. Если вам не доводилось использовать их, обратитесь к книге Джеффри Фридла (JeffreyFriedl) «Mastering Regular Expressions» (O’Reilly).
Это слишком объемная тема, чтобы пытаться охватить ее в данной книге.Вот как выглядел бы предыдущий запрос (найти всех сотрудников с фамилиями, начинающимися с «F» или «G») с использованием реализации регулярных выражений MySQL:mysql> SELECT emp_id, fname, lname> FROM employee> WHERE lname REGEXP '^[FG]';++++| emp_id | fname | lname|++++|5 | John | Gooding ||6 | Helen | Fleming ||9 | Jane | Grossman ||17 | Beth | Fowler |++++4 rows in set (0.00 sec)Оператор regexp принимает регулярное выражение (в данном примере'^[FG]') и применяет его к выражению, находящемуся в левой частиусловия (столбец lname). Теперь, с регулярным выражением, запрос содержит всего одно условие, а не два, как это было при использованиисимволов маски.86Глава 4.
ФильтрацияOracle Database 10g и SQL Server 2000 тоже поддерживают регулярныевыражения. При работе с Oracle Database 10g используется функцияregexp_like, а не оператор regexp, показанный в предыдущем примере.А SQL Server допускает использование регулярных выражений с оператором like.NULL: это слово из четырех букв…Я, сколько мог, оттягивал этот момент, но он настал: пора обратитьсяк теме, которую обычно встречают с опаской, неуверенностью и трепетом, – значение null. Null – это отсутствие значения.
Например, покасотрудник не уволен, в его столбце end_date таблицы employee должнобыть записано null. В данной ситуации нет значения, которое моглобы быть помещено в столбец end_date и имело бы смысл. Однако null –коварный тип, поскольку имеет несколько оттенков:НеприменимыйНапример, столбец с ID сотрудника для транзакции, которая выполняется с банкоматом.Значение еще не известноНапример, если в момент создания строки клиента федеральный IDнеизвестен.Значение не определеноНапример, если создается счет для продукта, который еще не былдобавлен в БД.Некоторые теоретики считают, что для каждой из этих (и других) ситуаций следовало бы использовать разные выражения,но по мнению большинства практикующих специалистов принескольких значениях null путаницы было бы гораздо больше.При работе с null необходимо помнить:• Выражение может быть нулевым (null), но оно никогда не можетбыть равным нулю.• Два null никогда не равны друг другу.Проверить выражение на значение null можно с помощью оператораis null, как показано в следующем примере:mysql> SELECT emp_id, fname, lname, superior_emp_id> FROM employee> WHERE superior_emp_id IS NULL;+++++| emp_id | fname | lname | superior_emp_id |+++++|1 | Michael | Smith |NULL |+++++1 row in set (0.00 sec)NULL: это слово из четырех букв…87Этот запрос возвращает всех сотрудников, у которых нет начальника(superior).
Вот тот же запрос, но вместо is null используется = null:mysql> SELECT emp_id, fname, lname, superior_emp_id> FROM employee> WHERE superior_emp_id = NULL;Empty set (0.01 sec)Как видите, запрос подвергается синтаксическому анализу и выполняется, но не возвращает ни одной строки. Это общая ошибка неопытныхSQLпрограммистов. Сервер БД не предупредит о ней, поэтому при создании условий проверки на null следует соблюдать осторожность.Проверить наличие значения в столбце можно с помощью оператораis not null:mysql> SELECT emp_id, fname, lname, superior_emp_id> FROM employee> WHERE superior_emp_id IS NOT NULL;+++++| emp_id | fname| lname| superior_emp_id |+++++|2 | Susan| Barker|1 ||3 | Robert | Tyler|1 ||4 | Susan| Hawthorne |3 ||5 | John| Gooding |4 ||6 | Helen| Fleming |4 ||7 | Chris| Tucker|6 ||8 | Sarah| Parker|6 ||9 | Jane| Grossman |6 ||10 | Paula| Roberts |4 ||11 | Thomas | Ziegler |10 ||12 | Samantha | Jameson |10 ||13 | John| Blake|4 ||14 | Cindy| Mason|13 ||15 | Frank| Portman |13 ||16 | Theresa | Markham |4 ||17 | Beth| Fowler|16 ||18 | Rick| Tulman|16 |+++++17 rows in set (0.01 sec)Эта версия запроса возвращает остальных 17 сотрудников, у которых,в отличие от Майкла Смита (Michael Smith), есть начальник.Прежде чем на время отложить рассмотрение null, было бы полезнымотметить еще одну потенциальную ловушку.
Предположим, требуетсяидентифицировать всех сотрудников, не подчиняющихся Хелен Флеминг (Helen Fleming), ID которой равен 6. Наверняка первым порывомбудет сделать следующее:mysql> SELECT emp_id, fname, lname, superior_emp_id> FROM employee> WHERE superior_emp_id != 6;88Глава 4. Фильтрация+++++| emp_id | fname| lname| superior_emp_id |+++++|2 | Susan| Barker|1 ||3 | Robert | Tyler|1 ||4 | Susan| Hawthorne |3 ||5 | John| Gooding |4 ||6 | Helen| Fleming |4 ||10 | Paula| Roberts |4 ||11 | Thomas | Ziegler |10 ||12 | Samantha | Jameson |10 ||13 | John| Blake|4 ||14 | Cindy| Mason|13 ||15 | Frank| Portman |13 ||16 | Theresa | Markham |4 ||17 | Beth| Fowler|16 ||18 | Rick| Tulman|16 |+++++14 rows in set (0.01 sec)Действительно, эти 14 сотрудников не работают под руководством Хелен Флеминг, но если внимательно посмотреть на данные, можно заметить, что здесь пропущен один сотрудник, также не являющийся подчиненным Хелен.
Это Майкл Смит, и в его столбце superior_emp_id стоитnull (потому что он «большая шишка»). Поэтому, чтобы правильно ответить на вопрос, необходимо учитывать вероятность того, что для некоторых строк столбец superior_emp_id может иметь значение null.mysql> SELECT emp_id, fname, lname, superior_emp_id> FROM employee> WHERE superior_emp_id != 6 OR superior_emp_id IS NULL;+++++| emp_id | fname| lname| superior_emp_id |+++++|1 | Michael | Smith|NULL ||2 | Susan| Barker|1 ||3 | Robert | Tyler|1 ||4 | Susan| Hawthorne |3 ||5 | John| Gooding |4 ||6 | Helen| Fleming |4 ||10 | Paula| Roberts |4 ||11 | Thomas | Ziegler |10 ||12 | Samantha | Jameson |10 ||13 | John| Blake|4 ||14 | Cindy| Mason|13 ||15 | Frank| Portman |13 ||16 | Theresa | Markham |4 ||17 | Beth| Fowler|16 ||18 | Rick| Tulman|16 |+++++15 rows in set (0.01 sec)89УпражненияТеперь результирующий набор включает всех 15 сотрудников, не подчиняющихся Хелен.
При работе с малознакомой базой данных не помешает выяснить, какие столбцы таблицы могут содержать null; этопоможет вам создавать правильные условия фильтрации, чтобы данные не смогли утекать сквозь пальцы.УпражненияСледующие упражнения проверят ваше понимание условий фильтрации. Решения ищите в приложении С.В первых двух упражнениях используются следующие данные о транзакциях:Txn_idTxn_dateAccount_idTxn_type_cdAmount120050222101CDT1000.00220050223102CDT525.75320050224101DBT100.00420050224103CDT55520050225101DBT50620050225103DBT25720050225102CDT125.37820050226103DBT10920050227101CDT754.1Какие ID транзакций возвращают следующие условия фильтрации?txn_date < '20050226' AND (txn_type_cd = 'DBT' OR amount > 100)4.2Какие ID транзакций возвращают следующие условия фильтрации?account_id IN (101,103) AND NOT (txn_type_cd = 'DBT' OR amount > 100)4.3Создайте запрос, выбирающий все счета, открытые в 2002 году.4.4Создайте запрос, выбирающий всех клиентовфизических лиц, второйбуквой фамилии которых является буква 'a' и есть 'e' в любой позиции после 'a'.Запрос к нескольким таблицамПоскольку реляционные БД предполагают расположение независимых сущностей в разных таблицах, необходим механизм сведения нескольких таблиц воедино в одном запросе.
Этот механизм известен каксоединение (join), и данная глава посвящена самому простому и наиболее распространенному соединению – внутреннему соединению (innerjoin). Все разнообразные типы соединений представлены в главе 10.Что такое соединение?Запросы к одной таблице, конечно, не редкость, но большинство запросов обращены к двум, трем или даже более таблицам. Для иллюстрации давайте рассмотрим описания таблиц employee и departmentи затем определим запрос, извлекающий данные из обеих:mysql> DESC employee;++++++| Field| Type| Null | Key | Default|++++++| emp_id| smallint(5) unsigned || PRI | NULL|| fname| varchar(20)||||| lname| varchar(20)||||| start_date| date||| 00000000 || end_date| date| YES || NULL|| superior_emp_id| smallint(5) unsigned | YES | MUL | NULL|| dept_id| smallint(5) unsigned | YES | MUL | NULL|| title| varchar(20)| YES || NULL|| assigned_branch_id | smallint(5) unsigned | YES | MUL | NULL|++++++9 rows in set (0.11 sec)mysql> DESC department;++++++Что такое соединение?91| Field | Type| Null | Key | Default |++++++| dept_id | smallint(5) unsigned || PRI | NULL|| name| varchar(20)||||++++++2 rows in set (0.03 sec)Скажем, требуется выбрать имя и фамилию каждого сотрудника, а также название отдела, в котором он работает.
Поэтому запрос должен будет извлекать столбцы employee.fname, employee.lname и department.name.Но как можно получить данные двух таблиц одним запросом? Ответкроется в столбце employee.dept_id, в котором хранится ID отдела каждого сотрудника (более формально, столбец employee.dept_id являетсявнешним ключом, ссылающимся на таблицу department). Запрос, который вскоре будет представлен, указывает серверу использовать столбец employee.dept_id как мост между таблицами employee и department,обеспечивая таким образом возможность включения столбцов обеихтаблиц в результирующий набор запроса.
Такой тип операции называется соединением.Декартово произведениеНачнем с самого простого: поместим таблицы employee и departmentв блок from запроса и посмотрим, что произойдет. Вот запрос, выбирающий имена и фамилии сотрудников, а также название отдела. Здесьв блоке from указаны обе таблицы, разделенные ключевым словом join:mysql> SELECT e.fname, e.lname, d.name> FROM employee e JOIN department d;++++| fname| lname| name|++++| Michael | Smith| Operations|| Susan| Barker| Operations|| Robert | Tyler| Operations|| Susan| Hawthorne | Operations|| John| Gooding | Operations|| Helen| Fleming | Operations|| Chris| Tucker| Operations|| Sarah| Parker| Operations|| Jane| Grossman | Operations|| Paula| Roberts | Operations|| Thomas | Ziegler | Operations|| Samantha | Jameson | Operations|| John| Blake| Operations|| Cindy| Mason| Operations|| Frank| Portman | Operations|| Theresa | Markham | Operations|| Beth| Fowler| Operations|| Rick| Tulman| Operations|92Глава 5.
Запрос к нескольким таблицам| Michael | Smith| Loans|| Susan| Barker| Loans|| Robert | Tyler| Loans|| Susan| Hawthorne | Loans|| John| Gooding | Loans|| Helen| Fleming | Loans|| Chris| Tucker| Loans|| Sarah| Parker| Loans|| Jane| Grossman | Loans|| Paula| Roberts | Loans|| Thomas | Ziegler | Loans|| Samantha | Jameson | Loans|| John| Blake| Loans|| Cindy| Mason| Loans|| Frank| Portman | Loans|| Theresa | Markham | Loans|| Beth| Fowler| Loans|| Rick| Tulman| Loans|| Michael | Smith| Administration || Susan| Barker| Administration || Robert | Tyler| Administration || Susan| Hawthorne | Administration || John| Gooding | Administration || Helen| Fleming | Administration || Chris| Tucker| Administration || Sarah| Parker| Administration || Jane| Grossman | Administration || Paula| Roberts | Administration || Thomas | Ziegler | Administration || Samantha | Jameson | Administration || John| Blake| Administration || Cindy| Mason| Administration || Frank| Portman | Administration || Theresa | Markham | Administration || Beth| Fowler| Administration || Rick| Tulman| Administration |++++54 rows in set (0.00 sec)Хм… у нас только 18 сотрудников и 3 разных отдела.