- •Глава 3. Учебное пособие по MySql
- •3.1. Подсоединение к серверу и отсоединение от него
- •3.2. Ввод запросов
- •3.3. Создание и использование базы данных
- •3.3.1. Создание и выбор базы данных
- •3.3.2. Создание таблицы
- •3.3.3. Загрузка данных в таблицу
- •3.3.4. Выборка информации из таблицы
- •3.3.4.1. Выборка всех данных
- •3.3.4.2. Выборка определенных строк
- •3.3.4.3. Выборка определенных столбцов
- •3.3.4.4. Сортировка строк
- •3.3.4.5. Вычисление дат
- •3.3.4.6. Работа с значениями null
- •3.3.4.7. Сравнение по шаблонам
- •3.3.4.8. Подсчет строк
- •3.3.4.9. Использование нескольких таблиц
- •3.4. Получение информации о базах данных и таблицах
- •3.5. Примеры стандартных запросов
- •3.5.1. Максимальное значение столбца
- •3.5.2. Строка, содержащая максимальное значение некоторого столбца
- •3.5.3. Максимальное значение столбца для группы
- •3.5.4. Строка, содержащая максимальное значение некоторого столбца
- •3.5.5. Использование пользовательских переменных
- •3.5.6. Использование внешних ключей
- •3.5.7. Поиск по двум ключам
- •3.5.8. Подсчет посещений за день
- •3.5.9. Использование атрибута auto_increment
- •3.6. Использование mysql в пакетном режиме
- •3.7. Запросы проекта 'Близнецы' (Twin Project)
- •3.7.1. Поиск нераспределенных близнецов
- •3.7.2. Вывод таблицы состояний пар близнецов
- •3.8. Использование MySql совместно с Apache
3.3.4.6. Работа с значениями null
К NULL-значениям нужно привыкнуть. По идее, NULL обозначает отсутствующее или неизвестное значение и обрабатывается отличным от других значений образом. Проверить значение на равенство NULL с помощью обычных арифметических операторов сравнения (=, < или <>) нельзя. Это отлично иллюстрирует следующий запрос:
mysql> SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL;
+----------+-----------+----------+----------+
| 1 = NULL | 1 <> NULL | 1 < NULL | 1 > NULL |
+----------+-----------+----------+----------+
| NULL | NULL | NULL | NULL |
+----------+-----------+----------+----------+
Очевидно, что от таких сравнений значащих результатов ожидать нечего. Вместо этого нужно пользоваться операторами IS NULL и IS NOT NULL:
mysql> SELECT 1 IS NULL, 1 IS NOT NULL;
+-----------+---------------+
| 1 IS NULL | 1 IS NOT NULL |
+-----------+---------------+
| 0 | 1 |
+-----------+---------------+
Отметим: в MySQL 0 или NULL приравнивается к логическому false, а все остальное - к true. По умолчанию значение "истина" для булевого оператора равно 1.
Именно из-за того, что при работе с NULL действуют особые правила, в предыдущем разделе для поиска умерших животных использовалось выражение death IS NOT NULL, а не death <> NULL.
Два NULL-значения считаются одинаковыми в GROUP BY.
При выполнении ORDER BY, NULL-значения идут в первую очередь если вы выполняете ORDER ... ASC и в последнюю - если ORDER BY ... DESC.
Обратите внимание, что в MySQL 4.0.2 - 4.0.10, NULL-значения всегда возвращались в первую очередь, вне зависимости от сортировки.
3.3.4.7. Сравнение по шаблонам
В MySQL реализовано стандартное для SQL сравнение по шаблонам, а также особый тип такого сравнения - он основан на использовании выражений, подобных применяющимся в служебных программах Unix (таких, как vi, grep и sed).
В SQL при сравнении по шаблону символ ‘_’ обозначает любой одиночный символ, а ‘%’ - определенное количество символов (включая ноль символов). В MySQL в SQL-шаблонах по умолчанию не учитывается регистр символов. При работе с шаблонами SQL использование операторов = или <> не допускается, вместо этого применяются операторы сравнения LIKE или NOT LIKE.
Найти все имена, начинающиеся с ‘b’, можно следующим образом:
mysql> SELECT * FROM pet WHERE name LIKE "b%";
+--------+--------+---------+------+------------+------------+
| name | owner | species | sex | birth | death |
+--------+--------+---------+------+------------+------------+
| Buffy | Harold | dog | f | 1989-05-13 | NULL |
| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
+--------+--------+---------+------+------------+------------+
Найти все имена, заканчивающиеся на 'fy', можно следующим образом:
mysql> SELECT * FROM pet WHERE name LIKE "%fy";
+--------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth | death |
+--------+--------+---------+------+------------+-------+
| Fluffy | Harold | cat | f | 1993-02-04 | NULL |
| Buffy | Harold | dog | f | 1989-05-13 | NULL |
+--------+--------+---------+------+------------+-------+
Найти все имена, содержащие ‘w’, можно следующим образом:
mysql> SELECT * FROM pet WHERE name LIKE "%w%";
+----------+-------+---------+------+------------+------------+
| name | owner | species | sex | birth | death |
+----------+-------+---------+------+------------+------------+
| Claws | Gwen | cat | m | 1994-03-17 | NULL |
| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
| Whistler | Gwen | bird | NULL | 1997-12-09 | NULL |
+----------+-------+---------+------+------------+------------+
Найти все имена, содержащие ровно пять символов, можно при помощи шаблонного символа ‘_’:
mysql> SELECT * FROM pet WHERE name LIKE "_____";
+-------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen | cat | m | 1994-03-17 | NULL |
| Buffy | Harold | dog | f | 1989-05-13 | NULL |
+-------+--------+---------+------+------------+-------+
Во втором типе шаблонов, предусмотренных в MySQL, используются расширенные регулярные выражения. При поиске совпадений на основе такого шаблона шаблоном нужно пользоваться операторами REGEXP и NOT REGEXP (или их синонимами - RLIKE и NOT RLIKE).
Ниже приведены некоторые характеристики расширенных регулярных выражений:
‘.’ обозначает любой символ.
Класс символов '[...]' обозначает любой из символов в скобках. Например, '[abc]' обозначает ‘a’, ‘b’ или ‘c’. Набор символов можно обозначить с помощью дефиса. '[a-z]' обозначает любую букву нижнего регистра, а '[0-9]' - любую цифру.
‘*’ обозначает ноль или более экземпляров символа, стоящего перед ним. Например, 'x*' обозначает любое количество символов ‘x’, '[0-9]*' обозначает любое количество цифр, а '.*' - любое количество любых символов.
Для шаблона выдается совпадение, если поисковый контекст обнаружен в любой из частей значения, в котором производится поиск (для шаблонов SQL совпадение выдается только в случае, если совпадает все значение).
``Закрепить'' шаблон так, чтобы проверять совпадения с началом или концом значения можно с помощью символов ‘^’ (начало) или ‘$’ (конец), которые располагаются в начале или в конце шаблона соответственно.
Чтобы продемонстрировать работу регулярных выражений, приведенные выше запросы LIKE здесь переписаны с использованием REGEXP.
Найти все имена, начинающиеся с ‘b’, можно при помощи символа ‘^’, привязывающего шаблон к началу имени:
mysql> SELECT * FROM pet WHERE name REGEXP "^b";
+--------+--------+---------+------+------------+------------+
| name | owner | species | sex | birth | death |
+--------+--------+---------+------+------------+------------+
| Buffy | Harold | dog | f | 1989-05-13 | NULL |
| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
+--------+--------+---------+------+------------+------------+
В версиях MySQL до 3.23.4 REGEXP учитывает регистр символов, и приведенный запрос не возвратит никаких результатов. Для поиска символов ‘b’ верхнего или нижнего регистра воспользуйтесь следующим запросом:
mysql> SELECT * FROM pet WHERE name REGEXP "^[bB]";
Начиная с версии MySQL 3.23.4, заставить REGEXP учитывать регистр символов можно с помощью ключевого слова BINARY. В этом запросе положительный результат поиска будет получен только при обнаружении символа 'b' нижнего регистра в начале имени:
mysql> SELECT * FROM pet WHERE name REGEXP BINARY "^b";
Найти все имена, заканчивающиеся на 'fy', можно при помощи символа ‘$’, привязывающего шаблон к концу имени:
mysql> SELECT * FROM pet WHERE name REGEXP "fy$";
+--------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth | death |
+--------+--------+---------+------+------------+-------+
| Fluffy | Harold | cat | f | 1993-02-04 | NULL |
| Buffy | Harold | dog | f | 1989-05-13 | NULL |
+--------+--------+---------+------+------------+-------+
Найти все имена, содержащие символ ‘w’ любого регистра, можно так:
mysql> SELECT * FROM pet WHERE name REGEXP "w";
+----------+-------+---------+------+------------+------------+
| name | owner | species | sex | birth | death |
+----------+-------+---------+------+------------+------------+
| Claws | Gwen | cat | m | 1994-03-17 | NULL |
| Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 |
| Whistler | Gwen | bird | NULL | 1997-12-09 | NULL |
+----------+-------+---------+------+------------+------------+
Поскольку регулярное выражение выдает положительный результат при совпадении шаблона с любым фрагментом значения, в приведенном выше примере привязывать поиск к любому из концов имени для сравнения полного значения с шаблоном, как это пришлось бы делать для шаблона SQL, не нужно.
Найти все имена, содержащие ровно пять символов, можно, если привязать поиск к началу и концу имени с помощью символов ‘^’ и ‘$’ и поставить пять символов ‘.’ между ними:
mysql> SELECT * FROM pet WHERE name REGEXP "^.....$";
+-------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen | cat | m | 1994-03-17 | NULL |
| Buffy | Harold | dog | f | 1989-05-13 | NULL |
+-------+--------+---------+------+------------+-------+
Предыдущий запрос можно записать и при помощи оператора '{n}' (``повторить-n-раз''):
mysql> SELECT * FROM pet WHERE name REGEXP "^.{5}$";
+-------+--------+---------+------+------------+-------+
| name | owner | species | sex | birth | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen | cat | m | 1994-03-17 | NULL |
| Buffy | Harold | dog | f | 1989-05-13 | NULL |
+-------+--------+---------+------+------------+-------+
