The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Каталог документации / Раздел "Базы данных, SQL" / Оглавление документа

2 Введение в MySQL

Эта глава обеспечивает введение в MySQL, показывая, как использовать клиент mysql, чтобы создавать и использовать простую базу данных. mysql (иногда упоминаемый как "terminal monitor" или "monitor") представляет собой интерактивную программу, которая позволяет Вам соединяться с сервером MySQL, выполнять запросы и просматривать результаты. Она может также использоваться в пакетном режиме: Вы помещаете Ваши запросы в файл заранее, затем сообщаете, чтобы клиент mysql выполнил содержимое файла. Оба пути использования будут здесь рассмотрены.

Чтобы увидеть список параметров mysql, вызовите его с опцией --help:

shell> mysql --help

Эта глава предполагает, что mysql установлен на Вашей машине, и что сервер MySQL доступен.

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

2.1 Соединение с сервером

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

shell> mysql -h host -u user -p
Enter password: ********

Здесь ******** представляет Ваш пароль. Введите его, когда mysql отобразит сообщение Enter password:.

Если это работает, Вы должны увидеть некоторую вводную информацию, сопровождаемую подсказкой mysql>:

shell> mysql -h host -u user -p
Enter password: ********
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 459 to server version: 3.22.20a-log

Type 'help' for help.

mysql>

Подсказка сообщает Вам, что mysql готов принять команды.

Некоторые инсталляции MySQL позволяют пользователям соединяться как анонимным (неназванным) пользователям с сервером на локальной машине. Если у Вас дело обстоит именно так, Вы можете соединиться с таким сервером, вызывая mysql без параметров:

shell> mysql

После того, как Вы успешно соединились, Вы можете разъединять соединение в любое время, набрав команду QUIT в ответ на подсказку mysql>:

mysql> QUIT
Bye

Вы можете также разъединять связь, нажимая Control-D.

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

2.2 Ввод запросов

В этой точке более важно выяснить немного относительно того, как выдавать запросы, чем правильно создавать базы данных. Этот раздел описывает базисные принципы ввода команд, использование нескольких запросов, которые Вы можете испытывать, чтобы ознакомиться с тем, как работает клиент mysql.

Имеется простая команда, которая просит, чтобы сервер сообщил свою версию и текущую дату. Напечатайте это как показано ниже после подсказки mysql> и нажмите клавишу RETURN:

mysql> SELECT VERSION(), CURRENT_DATE;
+--------------+--------------+
| version()    | CURRENT_DATE |
+--------------+--------------+
| 3.22.20a-log | 1999-03-19   |
+--------------+--------------+
1 row in set (0.01 sec)
mysql>

Этот запрос иллюстрирует несколько вещей относительно mysql:

Ключевые слова могут быть введены в любом регистре. Следующие запросы эквивалентны:

mysql> SELECT VERSION(), CURRENT_DATE;
mysql> select version(), current_date;
mysql> SeLeCt vErSiOn(), current_DATE;

Имеется другой запрос. Он показывает, что Вы можете использовать mysql как простой калькулятор:

mysql> SELECT SIN(PI()/4), (4+1)*5;
+-------------+---------+
| SIN(PI()/4) | (4+1)*5 |
+-------------+---------+
|    0.707107 |      25 |
+-------------+---------+

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

mysql> SELECT VERSION(); SELECT NOW();
+--------------+
| version()    |
+--------------+
| 3.22.20a-log |
+--------------+
+---------------------+
| NOW()               |
+---------------------+
| 1999-03-19 00:15:33 |
+---------------------+

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

Имеется простая инструкция с длинной строкой:

mysql> SELECT
    -> USER()
    -> ,
    -> CURRENT_DATE;
+--------------------+--------------+
| USER()             | CURRENT_DATE |
+--------------------+--------------+
| joesmith@localhost | 1999-03-18   |
+--------------------+--------------+

В этом примере обратите внимание, как подсказка изменяется с mysql> на -> после того, как Вы вводите первую строку запроса. Этим mysql указывает, что пока не видел полную инструкцию и ждет остальное. Подсказка Ваш друг потому, что обеспечивает ценную обратную связь. Если Вы используете эту обратную связь, Вы будете всегда знать, чего ждет от Вас mysql.

Если Вы решаете, что Вы не хотите выполнять команду, но находитесь в процессе ввода, отмените ее вводом \c:

mysql> SELECT
    -> USER()
    -> \c
mysql>

Здесь также обратите внимание на подсказку. Она переключилась назад в mysql> после ввода \c, обеспечивая обратную связь, чтобы указать, что mysql готов для новой команды.

Следующая таблица показывает все подсказки и обобщает их смысл:

ПодсказкаСмысл
mysql>Ожидание новой команды
->Ожидание следующей строки многострочной команды
'>Ожидание следующей строки при сборе строки, которая начинается с одиночной кавычки (')
">Ожидание следующей строки при сборе строки, которая начинается с двойной кавычки (")

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

mysql> SELECT USER()
    ->

Если это случается с Вами (Вы думаете, что ввели оператор, но единственный ответ представляет собой подсказку ->), наиболее вероятно, что mysql ждет точку с запятой. Введите точку с запятой, чтобы завершить инструкцию, и mysql ее выполнит:

mysql> SELECT USER()
    -> ;
+--------------------+
| USER()             |
+--------------------+
| joesmith@localhost |
+--------------------+

Подсказки '> и "> появляются при работе со строкой в кавычках. В MySQL Вы можете писать строки в символах ' или " (например, 'hello' или "goodbye"), и mysql позволяет Вам вводить длинные строки в виде нескольких коротких строк. Когда Вы видите подсказку '> или ">, это означает, что Вы ввели строку, которая начинается с символа кавычки ' или ", но еще не ввели вторую кавычку, которая завершает эту строку. Это также может сообщать и об ошибке:

mysql> SELECT * FROM my_table WHERE name="Smith AND age < 30;
    ">

Если Вы вводите эту инструкцию SELECT, то нажатие RETURN ничего не вернет. Вместо того, чтобы задаваться вопросом, почему этот запрос так долго выполняется, обратите внимание на подсказку ">. Это сообщает Вам, что mysql ожидает увидеть остальную часть незавершенной строки. Вы видите ошибку в инструкции? Строка "Smith пропускает вторую кавычку.

Что делать? Самая простая вещь: отменить команду. Однако, Вы не можете в этом случае просто напечатать \c, так как mysql интерпретирует это как часть, которая вводится! Вместо этого, введите заключительный символ кавычки (чтобы mysql понял, что Вы закончили строку), а уж потом \c:

mysql> SELECT * FROM my_table WHERE name = "Smith AND age < 30;
    "> "\c
mysql>

Подсказка изменяется обратно на mysql>, указывая, что mysql готов для новой команды.

Важно знать, что сообщают подсказки '> и ">, так как если Вы по ошибке вводите незавершенную строку, любые дальнейшие строки, которые Вы введете, будут игнорироваться mysql, включая строку QUIT! Это может крепко запутать, особенно, если Вы не знаете, что должны ввести кавычку завершения прежде, чем Вы сможете отменить текущую команду.

2.3 Создание и использование баз данных

Теперь, когда Вы знаете, как вводить команды, самое время обратиться к базе данных.

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

База данных животных будет простой, но нетрудно думать о реальных ситуациях, в которых подобный тип базы данных мог бы использоваться. Например, база данных, подобная этой, могла бы использоваться фермером, чтобы следить за домашним скотом, или ветеринаром, чтобы наблюдать за пациентами. Дистрибутив базы животных, содержащий некоторые из запросов и типовых данных, используемых в следующих разделах, может быть получен с Web-сайта MySQL в сжатом tar формате или в Zip-формате.

Используйте инструкцию SHOW, чтобы выяснить то, какие базы данных в настоящее время существуют на Вашем сервере:

mysql> SHOW DATABASES;
+----------+
| Database |
+----------+
| mysql    |
| test     |
| tmp      |
+----------+

Список баз данных, вероятно, иной на Вашей машине, но базы с именами mysql и test, вероятно, будут среди них. База данных mysql вообще обязательна потому, что она описывает привилегии доступа пользователей. База данных test часто обеспечивается как рабочая область для начинающих пользователей (лягушатник). Именно там проводятся разные "опыты со взрывами".

Если существует база данных test, попробуйте обратиться к ней:

mysql> USE test
Database changed

Обратите внимание, что USE, подобно QUIT, не требует точки с запятой. Вы можете завершать такие инструкции точкой с запятой, если Вы находите это приятным, такой подход не несет никакого вреда. Инструкция USE должна быть задана в одной строке.

Вы можете использовать базу данных тестов test (если Вы имеете доступ к ней) для примеров, но все, что Вы там насоздавали, может быть удалено кем-либо еще с доступом к ней. По этой причине, Вы должны, вероятно, спросить у Вашего администратора MySQL разрешения использовать собственную базу данных. Предположим, что Вы хотите вызвать Ваш звероуголок (menagerie). Администратор должен выполнить такую команду:

mysql> GRANT ALL ON menagerie.* TO your_mysql_name;

Здесь your_mysql_name представляет собой имя пользователя MySQL, назначенное Вам.

2.3.1 Создание и выбор баз данных

Если администратор создал базу данных для Вас и установил Ваши права доступа, Вы можете начинать использовать ее. Иначе, Вы должны создать базу данных самостоятельно. Например:

mysql> CREATE DATABASE menagerie;

Под Unix имена баз данных чувствительны к регистру (в отличие от ключевых слов SQL), так что Вы должны всегда обращаться к Вашей базе данных как к menagerie, но не как Menagerie, MENAGERIE или еще как-то. Это также верно для имен таблицы. Под Windows это ограничение не применяется, хотя Вы должны обращаться к базам данных и таблицам, используя тот же самый регистр символов в течение запроса.

Создание базы данных не выбирает ее для использования, Вы должны сделать это явно. Чтобы объявить menagerie текущей (актуальной) базой данных, используйте эту команду:

mysql> USE menagerie
Database changed

Ваша база данных должна быть создана только однажды, но Вы должны выбирать ее для использования каждый раз, когда Вы начинаете сеанс mysql. Вы можете сделать это, выдавая инструкцию USE как показано выше. Альтернативно, Вы можете выбирать базу данных в командной строке, когда Вы вызываете mysql. Только определите имя после любых параметров подключения к серверу, которые Вы должны обеспечить. Например:

shell> mysql -h host -u user -p menagerie
Enter password: ********

Обратите внимание, что menagerie не Ваш пароль. Если Вы хотите указать пароль в командной строке после опции -p, Вы должны сделать это без пробела (например, как -pmypassword, но не как -p mypassword). Однако, помещение Вашего пароля в командную строку не рекомендуется потому, что это выставит его на всеобщее обозрение всем пользователям Вашей машины.

2.3.2 Создание таблицы

Создание базы данных дело простое, но сейчас база пустая, о чем и сообщает команда SHOW TABLES:

mysql> SHOW TABLES;
Empty set (0.00 sec)

Наиболее трудная часть этого дела: решить, какова будет структура Вашей базы данных, в каких таблицах Вы будете нуждаться, и какие столбцы будут в каждой из них.

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

Каков приблизительный возраст? Это могло бы быть интересным, но лучше не вписывать такие данные в таблицу. Возраст изменяется, а это означает, что Вы должны будете часто модифицировать Ваши записи. Вместо этого лучше сохранить фиксированное значение, типа даты рождения. Затем всякий раз, когда Вы нуждаетесь в данных о возрасте, Вы можете вычислить его как различие (но не разность!) между текущей датой и датой рождения. MySQL обеспечивает функции для выполнения арифметики даты, так что это нетрудно. Сохранение даты рождения имеет также и другие преимущества:

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

Используйте инструкцию CREATE TABLE, чтобы определить размещение Вашей таблицы:

mysql> CREATE TABLE pet (name VARCHAR(20), owner VARCHAR(20),
    -> species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);

VARCHAR представляет собой хороший выбор для столбцов имени, владельца и разновидности потому, что значения столбца изменяются по длине. Длины столбцов name, owner и species не должны превышать 20 символов. Вообще-то, для этого типа столбцов Вы можете выбирать любую длину от 1 до 255, какая кажется наиболее приемлемой Вам. Если Вы делаете столбец недостаточных размеров, а позже окажется, что Вы нуждаетесь в более длинном поле, MySQL обеспечивает инструкцию ALTER TABLE.

Пол животных можно представить разными путями, например, "m" и "f" или словами "male" и "female". Самое простое: использовать одиночные символы "m" и "f".

Использование типа данных DATE для столбцов рождения и гибели (birth и death) явно довольно очевидный выбор.

Теперь, когда Вы создали таблицу, SHOW TABLES должен произвести некоторый вывод:

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| pet                 |
+---------------------+

Чтобы проверить, что Ваша таблица была создана тем путем, каким Вы ожидали, используйте инструкцию DESCRIBE:

mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name    | varchar(20) | YES  |     | NULL    |       |
| owner   | varchar(20) | YES  |     | NULL    |       |
| species | varchar(20) | YES  |     | NULL    |       |
| sex     | char(1)     | YES  |     | NULL    |       |
| birth   | date        | YES  |     | NULL    |       |
| death   | date        | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+

Вы можете использовать DESCRIBE в любое время, например, если Вы забываете имена столбцов в Вашей таблице, или каких они типов.

2.3.3 Загрузка данных в таблицу

После создания Вашей таблицы Вы должны заполнить ее. Инструкции LOAD DATA и INSERT полезны для этого.

Предположим, что Ваши записи о живности могут быть описаны как показано ниже. Заметьте, что MySQL ожидает даты в формате YYYY-MM-DD, это может быть отлично от того, к чему Вы привыкли.

nameowner speciessexbirth death
FluffyHaroldкошкаf1993-02-04
ClawsGwenкошкаm1994-03-17
BuffyHaroldсобакаf1989-05-13
FangBennyсобакаm1990-08-27
BowserDianeсобакаm1989-08-31 1995-07-29
ChirpyGwenптичкаf1998-09-11
WhistlerGwenптичка1997-12-09
SlimBennyзмеяm1996-04-29

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

Вы могли бы создать текстовый файл pet.txt, содержащий одну запись на строку, со значениями, отделяемыми позициями табуляции, указанными в том порядке, в котором столбцы были перечислены в инструкции CREATE TABLE. Для отсутствующих значений (типа неизвестного пола или дат гибели для животных, которые все еще живут), Вы можете использовать значения NULL. Чтобы представить их в Вашем текстовом файле, используйте \N. Например, запись для птички Whistler выглядит примерно так (пробелом я обозначил табуляцию):

Whistler Gwen птичка \N 1997-12-09 \N

Чтобы загрузить текстовый файл pet.txt в таблицу pet, используйте эту команду:

mysql> LOAD DATA LOCAL INFILE "pet.txt" INTO TABLE pet;

Вы можете определять разделитель значений столбцов и маркер конца строки в инструкции явно LOAD DATA, если Вы желаете, но значениями по умолчанию являются табуляция и перевод строки. Они достаточны, чтобы правильно прочитать файл pet.txt.

Когда Вы хотите добавить новые записи по одной, полезна инструкция INSERT. В самой простой ее форме Вы обеспечиваете значения для каждого столбца в том порядке, в котором столбцы были перечислены в инструкции CREATE TABLE. Предположим, что Diane получила нового хомяка Puffball. Вы можете добавить новую запись, используя инструкцию INSERT, подобно этому:

mysql> INSERT INTO pet
    -> VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);

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

Из этого примера Вы видите, что для непосредственной загрузки в таблицу пришлось бы печатать довольно много. Инструкция LOAD DATA сберегла много времени.

2.3.4 Получение информации из таблицы

Инструкция SELECT используется, чтобы получить информацию из таблицы. Общая форма инструкции:

SELECT what_to_select FROM which_table WHERE conditions_to_satisfy

what_to_select указывает то, что Вы хотите увидеть. Это может быть список столбцов или *, чтобы указать все столбцы. which_table указывает таблицу, из которой Вы хотите получить данные. Предложение WHERE факультативно. Если оно представлено, conditions_to_satisfy определяет условия, которым должны удовлетворять искомые строки.

2.3.4.1 Выбор всех данных

Самая простая форма SELECT получает все из таблицы:

mysql> SELECT * FROM pet;
+----------+--------+---------+------+------------+------------+
| name     | owner  | species | sex  | birth      | death      |
+----------+--------+---------+------+------------+------------+
| Fluffy   | Harold | cat     | f    | 1993-02-04 | NULL       |
| Claws    | Gwen   | cat     | m    | 1994-03-17 | NULL       |
| Buffy    | Harold | dog     | f    | 1989-05-13 | NULL       |
| Fang     | Benny  | dog     | m    | 1990-08-27 | NULL       |
| Bowser   | Diane  | dog     | m    | 1998-08-31 | 1995-07-29 |
| Chirpy   | Gwen   | bird    | f    | 1998-09-11 | NULL       |
| Whistler | Gwen   | bird    | NULL | 1997-12-09 | NULL       |
| Slim     | Benny  | snake   | m    | 1996-04-29 | NULL       |
| Puffball | Diane  | hamster | f    | 1999-03-30 | NULL       |
+----------+--------+---------+------+------------+------------+

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

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

2.3.4.2 Выбор конкретных строк

Вы можете выбирать только специфические строки из Вашей таблицы. Например, если Вы хотите проверить изменение, которое Вы сделали в дате рождения Bowser, выберите запись для Bowser подобно этому:

mysql> SELECT * FROM pet WHERE name = "Bowser";
+--------+-------+---------+------+------------+------------+
| name   | owner | species | sex  | birth      | death      |
+--------+-------+---------+------+------------+------------+
| Bowser | Diane | dog     | m    | 1989-08-31 | 1995-07-29 |
+--------+-------+---------+------+------------+------------+

Вывод подтверждает, что год теперь правильно зарегистрирован как 1989, а не 1998.

Сравнения строк обычно не чувствительны к регистру, так что Вы можете определять имя как "bowser", "BOWSER" или как хотите. Результат запроса будет тот же самый.

Вы можете определять произвольные условия на любом столбце, не только name. Например, если Вы хотите знать, какие животные были рождены после 1998 года, проверьте столбец birth:

mysql> SELECT * FROM pet WHERE birth >= "1998-1-1";
+----------+-------+---------+-----+------------+-------+
| name     | owner | species | sex | birth      | death |
+----------+-------+---------+-----+------------+-------+
| Chirpy   | Gwen  | bird    | f   | 1998-09-11 | NULL  |
| Puffball | Diane | hamster | f   | 1999-03-30 | NULL  |
+----------+-------+---------+-----+------------+-------+

Вы можете объединять условия, например, найти самок собак:

mysql> SELECT * FROM pet WHERE species="dog" AND sex="f";
+-------+--------+---------+-----+------------+-------+
| name  | owner  | species | sex | birth      | death |
+-------+--------+---------+-----+------------+-------+
| Buffy | Harold | dog     | f   | 1989-05-13 | NULL  |
+-------+--------+---------+-----+------------+-------+

Предшествующий запрос использует логический оператор AND. Имеется также оператор OR:

mysql> SELECT * FROM pet WHERE species="snake" OR species="bird";
+----------+-------+---------+------+------------+-------+
| name     | owner | species | sex  | birth      | death |
+----------+-------+---------+------+------------+-------+
| Chirpy   | Gwen  | bird    | f    | 1998-09-11 | NULL  |
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL  |
| Slim     | Benny | snake   | m    | 1996-04-29 | NULL  |
+----------+-------+---------+------+------------+-------+

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

mysql> SELECT * FROM pet WHERE (species = "cat" AND sex = "m")
    -> OR (species = "dog" AND sex = "f");
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

2.3.4.3 Выбор произвольных столбцов

Если Вы не хотите видеть все строки из Вашей таблицы, только укажите столбцы, в которых вы заинтересованы, отделяя их запятыми. Например, если Вы хотите знать, когда Ваши животные были рождены, выберите столбцы name и birth:

mysql> SELECT name, birth FROM pet;
+----------+------------+
| name     | birth      |
+----------+------------+
| Fluffy   | 1993-02-04 |
| Claws    | 1994-03-17 |
| Buffy    | 1989-05-13 |
| Fang     | 1990-08-27 |
| Bowser   | 1989-08-31 |
| Chirpy   | 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim     | 1996-04-29 |
| Puffball | 1999-03-30 |
+----------+------------+

Чтобы выяснить, кто обладает домашним животным, используйте такой запрос:

mysql> SELECT owner FROM pet;
+--------+
| owner  |
+--------+
| Harold |
| Gwen   |
| Harold |
| Benny  |
| Diane  |
| Gwen   |
| Gwen   |
| Benny  |
| Diane  |
+--------+

Однако, обратите внимание, что запрос просто находит поле owner из каждой записи, и некоторые из них появляются больше, чем однажды. Чтобы минимизировать вывод, получите каждую уникальную запись вывода только однажды, добавляя ключевое слово DISTINCT:

mysql> SELECT DISTINCT owner FROM pet;
+--------+
| owner  |
+--------+
| Benny  |
| Diane  |
| Gwen   |
| Harold |
+--------+

Вы можете использовать предложение WHERE, чтобы объединить выбор строки с выбором столбца. Например, чтобы получить даты рождения только для кошек и собак, используйте запрос:

mysql> SELECT name, species, birth FROM pet
    -> WHERE species = "dog" OR species = "cat";
+--------+---------+------------+
| name   | species | birth      |
+--------+---------+------------+
| Fluffy | cat     | 1993-02-04 |
| Claws  | cat     | 1994-03-17 |
| Buffy  | dog     | 1989-05-13 |
| Fang   | dog     | 1990-08-27 |
| Bowser | dog     | 1989-08-31 |
+--------+---------+------------+

2.3.4.4 Сортировка строк

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

Отсортируем дни рождения нашей живности:

mysql> SELECT name, birth FROM pet ORDER BY birth;
+----------+------------+
| name     | birth      |
+----------+------------+
| Buffy    | 1989-05-13 |
| Bowser   | 1989-08-31 |
| Fang     | 1990-08-27 |
| Fluffy   | 1993-02-04 |
| Claws    | 1994-03-17 |
| Slim     | 1996-04-29 |
| Whistler | 1997-12-09 |
| Chirpy   | 1998-09-11 |
| Puffball | 1999-03-30 |
+----------+------------+

Чтобы сортировать в обратном порядке, добавьте к имени столбца, по которому Вы сортируете, ключевое слово DESC:

mysql> SELECT name, birth FROM pet ORDER BY birth DESC;
+----------+------------+
| name     | birth      |
+----------+------------+
| Puffball | 1999-03-30 |
| Chirpy   | 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim     | 1996-04-29 |
| Claws    | 1994-03-17 |
| Fluffy   | 1993-02-04 |
| Fang     | 1990-08-27 |
| Bowser   | 1989-08-31 |
| Buffy    | 1989-05-13 |
+----------+------------+

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

mysql> SELECT name, species, birth FROM pet ORDER BY species, birth DESC;
+----------+---------+------------+
| name     | species | birth      |
+----------+---------+------------+
| Chirpy   | bird    | 1998-09-11 |
| Whistler | bird    | 1997-12-09 |
| Claws    | cat     | 1994-03-17 |
| Fluffy   | cat     | 1993-02-04 |
| Fang     | dog     | 1990-08-27 |
| Bowser   | dog     | 1989-08-31 |
| Buffy    | dog     | 1989-05-13 |
| Puffball | hamster | 1999-03-30 |
| Slim     | snake   | 1996-04-29 |
+----------+---------+------------+

Обратите внимание, что ключевое слово DESC применяется только к имени столбца непосредственно перед ним (birth), а значения species сортируются в порядке возрастания.

2.3.4.5 Вычисление дат

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

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

mysql> SELECT name, birth, CURRENT_DATE,
    -> (YEAR(CURRENT_DATE)-YEAR(birth))
    -> -(RIGHT(CURRENT_DATE,5)<RIGHT(birth,5)) AS age FROM pet;
+----------+------------+--------------+------+
| name     | birth      | CURRENT_DATE | age  |
+----------+------------+--------------+------+
| Fluffy   | 1993-02-04 | 2001-08-29   |    8 |
| Claws    | 1994-03-17 | 2001-08-29   |    7 |
| Buffy    | 1989-05-13 | 2001-08-29   |   12 |
| Fang     | 1990-08-27 | 2001-08-29   |   11 |
| Bowser   | 1989-08-31 | 2001-08-29   |   11 |
| Chirpy   | 1998-09-11 | 2001-08-29   |    2 |
| Whistler | 1997-12-09 | 2001-08-29   |    3 |
| Slim     | 1996-04-29 | 2001-08-29   |    5 |
| Puffball | 1999-03-30 | 2001-08-29   |    2 |
+----------+------------+--------------+------+

Здесь YEAR() выделяет часть года даты, RIGHT() убирает пять символов, которые представляют часть MM-DD даты. Часть выражения, которое сравнивает значения MM-DD, выставляется в 1 или 0, что корректирует различие лет, если CURRENT_DATE стоит ранее в году, чем рождение (birth). Полное выражение несколько перегружено, так что псевдоним (age) используется, чтобы заставить столбец вывода обрести более читабельный заголовок.

Запрос работает, но результат мог бы быть просмотрен более легко, если строки были выведены в некотором порядке. Это может быть выполнено, добавляя предложение ORDER BY name, чтобы сортировать вывод:

mysql> SELECT name, birth, CURRENT_DATE,
    -> (YEAR(CURRENT_DATE)-YEAR(birth))
    -> -(RIGHT(CURRENT_DATE,5)<RIGHT(birth,5))
    -> AS age FROM pet ORDER BY name;
+----------+------------+--------------+------+
| name     | birth      | CURRENT_DATE | age  |
+----------+------------+--------------+------+
| Bowser   | 1989-08-31 | 2001-08-29   |   11 |
| Buffy    | 1989-05-13 | 2001-08-29   |   12 |
| Chirpy   | 1998-09-11 | 2001-08-29   |    2 |
| Claws    | 1994-03-17 | 2001-08-29   |    7 |
| Fang     | 1990-08-27 | 2001-08-29   |   11 |
| Fluffy   | 1993-02-04 | 2001-08-29   |    8 |
| Puffball | 1999-03-30 | 2001-08-29   |    2 |
| Slim     | 1996-04-29 | 2001-08-29   |    5 |
| Whistler | 1997-12-09 | 2001-08-29   |    3 |
+----------+------------+--------------+------+

Чтобы отсортировать вывод по возрасту (age), а не по имени (name), примените другое предложение ORDER BY:

mysql> SELECT name, birth, CURRENT_DATE,
    -> (YEAR(CURRENT_DATE)-YEAR(birth))
    -> -(RIGHT(CURRENT_DATE,5)<RIGHT(birth,5))
    -> AS age FROM pet ORDER BY age;
+----------+------------+--------------+------+
| name     | birth      | CURRENT_DATE | age  |
+----------+------------+--------------+------+
| Chirpy   | 1998-09-11 | 2001-08-29   |    2 |
| Puffball | 1999-03-30 | 2001-08-29   |    2 |
| Whistler | 1997-12-09 | 2001-08-29   |    3 |
| Slim     | 1996-04-29 | 2001-08-29   |    5 |
| Claws    | 1994-03-17 | 2001-08-29   |    7 |
| Fluffy   | 1993-02-04 | 2001-08-29   |    8 |
| Fang     | 1990-08-27 | 2001-08-29   |   11 |
| Bowser   | 1989-08-31 | 2001-08-29   |   11 |
| Buffy    | 1989-05-13 | 2001-08-29   |   12 |
+----------+------------+--------------+------+

Подобный запрос может использоваться, чтобы определить возраст для животных, которые умерли. Вы определяете такие случаи, проверяя, является или нет значение death равным NULL. Затем, для тех, которые не-NULL, вычислите разницу между death и birth:

mysql> SELECT name, birth, death,
    -> (YEAR(death)-YEAR(birth)) - (RIGHT(death,5)<RIGHT(birth,5))
    -> AS age
    -> FROM pet WHERE death IS NOT NULL ORDER BY age;
+--------+------------+------------+------+
| name   | birth      | death      | age  |
+--------+------------+------------+------+
| Bowser | 1989-08-31 | 1995-07-29 |    5 |
+--------+------------+------------+------+

Запрос использует death IS NOT NULL вместо death != NULL потому, что NULL специальное значение. Подробности в разделе "2.3.4.6 Работа со значениями NULL".

Что делать, если Вы хотите знать, какие животные имеют дни рождения в следующем месяце? Для этого типа вычисления, год и день не годятся. Вы просто хотите извлекать часть месяца из столбца birth. MySQL обеспечивает несколько функций извлечения частей даты, типа YEAR(), MONTH() и DAYOFMONTH(). Чтобы увидеть, как это работает, выполните простой запрос, который отображает значения birth и MONTH(birth):

mysql> SELECT name, birth, MONTH(birth) FROM pet;
+----------+------------+--------------+
| name     | birth      | MONTH(birth) |
+----------+------------+--------------+
| Fluffy   | 1993-02-04 |            2 |
| Claws    | 1994-03-17 |            3 |
| Buffy    | 1989-05-13 |            5 |
| Fang     | 1990-08-27 |            8 |
| Bowser   | 1989-08-31 |            8 |
| Chirpy   | 1998-09-11 |            9 |
| Whistler | 1997-12-09 |           12 |
| Slim     | 1996-04-29 |            4 |
| Puffball | 1999-03-30 |            3 |
+----------+------------+--------------+

Поиск животных с днями рождения в наступающем месяце прост. Предположим, что текущий месяц апрель. Значение month равно 4, и Вы ищете животных, рожденных в мае (month=5):

mysql> SELECT name, birth FROM pet WHERE MONTH(birth) = 5;
+-------+------------+
| name  | birth      |
+-------+------------+
| Buffy | 1989-05-13 |
+-------+------------+

Имеется маленькое осложнение, если текущий месяц декабрь. Здесь надо искать животных, рожденных в январе.

Вы можете даже написать запрос так, чтобы это работало независимо от того, каков текущий месяц. DATE_ADD() позволяет Вам добавлять интервал времени к заданной дате. Если Вы добавляете месяц к значению NOW(), а затем извлекаете часть месяца с помощью MONTH(), результатом как раз и будет тот месяц, в котором надо искать дни рождения:

mysql> SELECT name, birth FROM pet
    -> WHERE MONTH(birth) = MONTH(DATE_ADD(NOW(), INTERVAL 1 MONTH));

2.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.

2.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, которые являются синонимами).

Некоторые характеристики расширенных регулярных выражений:

Чтобы проиллюстрировать, как выполняется работа регулярных выражений, показанные выше запросы 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 Version 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} в операторе repeat-n-times:

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  |
+-------+--------+---------+------+------------+-------+

2.3.4.8 Подсчет строк

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

Подсчет общего количества животных, которых Вы имеете, аналогичен вопросу о том, сколько строк находятся в таблице pet? Дело в том, что имеется одна запись на домашнее животное. Функция COUNT() считает число не-NULL результатов, так что запрос для подсчета животных выглядит следующим образом:

mysql> SELECT COUNT(*) FROM pet;
+----------+
| COUNT(*) |
+----------+
|        9 |
+----------+

Ранее Вы нашли имена людей, которые имели домашние животных. Вы можете использовать COUNT(), если хотите выяснить, сколько домашних животных имеет каждый владелец:

mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
+--------+----------+
| owner  | COUNT(*) |
+--------+----------+
| Benny  |        2 |
| Diane  |        2 |
| Gwen   |        3 |
| Harold |        2 |
+--------+----------+

Обратите внимание на использование ключевого слова GROUP BY, чтобы сгруппировать вместе все записи для каждого владельца (owner). Без него все, что Вы получите, это сообщение об ошибках:

mysql> SELECT owner, COUNT(owner) FROM pet;
ERROR 1140 at line 1: Mixing of GROUP columns (MIN(),MAX(),COUNT()...)
with no GROUP columns is illegal if there is no GROUP BY clause

COUNT() и GROUP BY полезны для характеристики Ваших данных различными способами. Следующие примеры показывают различные способы выполнить операции переписи.

Число животных на разновидность:

mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
+---------+----------+
| species | COUNT(*) |
+---------+----------+
| bird    |        2 |
| cat     |        2 |
| dog     |        3 |
| hamster |        1 |
| snake   |        1 |
+---------+----------+

Число животных на пол:

mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
+------+----------+
| sex  | COUNT(*) |
+------+----------+
| NULL |        1 |
| f    |        4 |
| m    |        4 |
+------+----------+

В этом выводе NULL указывает неизвестный пол.

Число животных на комбинацию разновидности и пола:

mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | NULL |        1 |
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

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

mysql> SELECT species, sex, COUNT(*) FROM pet
    -> WHERE species = "dog" OR species = "cat" GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
+---------+------+----------+

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

mysql> SELECT species, sex, COUNT(*) FROM pet
    -> WHERE sex IS NOT NULL GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

2.3.4.9 Использование нескольких таблиц в одном запросе

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

Согласно этим данным инструкция CREATE TABLE для таблицы событий (event) могла бы выглядеть следующим образом:

mysql> CREATE TABLE event (name VARCHAR(20), date DATE,
    -> type VARCHAR(15), remark VARCHAR(255));

Как с таблицей pet, проще всего загрузить начальные записи, создав разграниченный табуляциями текстовый файл, содержащий информацию:

Fluffy1995-05-15Потомство4 котенка, 3 female, 1 male
Buffy1993-06-23Потомство5 щенков, 2 female, 3 male
Buffy1994-06-19Потомство3 щенка, 3 female
Chirpy1999-03-21ВетеринарНеобходимо выпрямление клюва
Slim1997-08-03ВетеринарСломано ребро
Bowser1991-10-12Конура
Fang1991-10-12Конура
Fang1998-08-28День рожденияПодарок: новая жевательная игрушка
Claws1998-03-17День рожденияПодарок: ошейник от блох
Whistler1998-12-09День рожденияПервый день рождения

Загрузите записи так:

mysql> LOAD DATA LOCAL INFILE "event.txt" INTO TABLE event;

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

Предположим, что Вы хотите выяснить возрасты каждого домашнего животного, когда они имели потомство. Таблица event указывает, когда это произошло, но чтобы вычислить возраст матери, Вы нуждаетесь в ее дате рождения. Поскольку это сохранено в таблице pet, Вы нуждаетесь в обеих таблицах для обработки запроса:

mysql> SELECT pet.name, (TO_DAYS(date)-TO_DAYS(birth))/365 AS age,
    -> remark FROM pet, event WHERE pet.name=event.name
    -> AND type="litter";
+--------+------+-----------------------------+
| name   | age  | remark                      |
+--------+------+-----------------------------+
| Fluffy | 2.27 | 4 kittens, 3 female, 1 male |
| Buffy  | 4.12 | 5 puppies, 2 female, 3 male |
| Buffy  | 5.10 | 3 puppies, 3 female         |
+--------+------+-----------------------------+

Итак, что тут происходит?

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

mysql> SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
    -> FROM pet AS p1, pet AS p2
    -> WHERE p1.species=p2.species AND p1.sex="f" AND p2.sex="m";
+--------+------+--------+------+---------+
| name   | sex  | name   | sex  | species |
+--------+------+--------+------+---------+
| Fluffy | f    | Claws  | m    | cat     |
| Buffy  | f    | Fang   | m    | dog     |
| Buffy  | f    | Bowser | m    | dog     |
+--------+------+--------+------+---------+

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

2.4 Получение информации о базах данных и таблицах

Что, если Вы забыли имя базы данных, или таблицы или ее структуру (например, как столбцы именованы)? MySQL решает эту проблему через несколько инструкций, которые обеспечивают информацию относительно баз данных и таблиц, которые это поддерживают.

Вы уже видели вызов SHOW DATABASES, который вносит в список базы данных, управляемые сервером. Чтобы выяснять, которая база данных в настоящее время выбрана, используйте функцию DATABASE():

mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| menagerie  |
+------------+

Если Вы не выбрали базу данных, результат пуст.

Чтобы выяснять какие таблицы хранит текущая база данных (например, когда Вы не уверены относительно имени таблицы), используйте эту команду:

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| event               |
| pet                 |
+---------------------+

Если Вы хотите выяснить что-то относительно структуры таблицы, команда DESCRIBE очень полезна. Она отображает информацию относительно каждого из столбцов таблицы:

mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name    | varchar(20) | YES  |     | NULL    |       |
| owner   | varchar(20) | YES  |     | NULL    |       |
| species | varchar(20) | YES  |     | NULL    |       |
| sex     | char(1)     | YES  |     | NULL    |       |
| birth   | date        | YES  |     | NULL    |       |
| death   | date        | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+

Field указывает имя столбца, Type тип данных для столбца, Null указывает, может или нет столбец содержать значения NULL, Key указывает, индексирован или нет столбец, а Default определяет значение столбца по умолчанию.

Если Вы имеете индексы на таблице, SHOW INDEX FROM tbl_name производит информацию относительно их.

2.5 Примеры общих запросов

Имеются примеры того, как решить некоторые общие проблемы с MySQL.

Некоторые из примеров используют таблицы shop, чтобы хранить цену каждого изделия (номер элемента, item) для некоторых торговцев (trader). Предположим, что каждый торговец имеет одну фиксированную цену на изделие, тогда пара (item, trader) является первичным ключом для записей.

Запустите инструмент командной строки mysql и выберите базу данных:

mysql your-database-name

В большинстве инсталляций MySQL Вы можете использовать имя базы данных test.

Вы можете создать таблицу для примера так:

CREATE TABLE shop (article INT(4) UNSIGNED ZEROFILL DEFAULT '0000'
             NOT NULL, dealer CHAR(20) DEFAULT '' NOT NULL,
             price DOUBLE(16,2) DEFAULT '0.00' NOT NULL,
             PRIMARY KEY(article, dealer));
INSERT INTO shop VALUES
   (1,'A',3.45),(1,'B',3.99),(2,'A',10.99),
   (3,'B',1.45),(3,'C',1.69),(3,'D',1.25),(4,'D',19.95);

Посмотрим данные примера:

mysql> SELECT * FROM shop;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0001 | A      |  3.45 |
|    0001 | B      |  3.99 |
|    0002 | A      | 10.99 |
|    0003 | B      |  1.45 |
|    0003 | C      |  1.69 |
|    0003 | D      |  1.25 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

2.5.1 Максимальное значение для столбца

Что является самым большим значением для элемента?

SELECT MAX(article) AS article FROM shop
+---------+
| article |
+---------+
|       4 |
+---------+

2.5.2 В какой строке хранится максимум некоего столбца?

Допустим, надо найти код, торговца и цену наиболее дорогого изделия.

В ANSI SQL это легко может быть выполнен подзапросом:

SELECT article, dealer, price FROM shop
       WHERE price=(SELECT MAX(price) FROM shop)

В MySQL (который еще не имеет поддержки вложенных запросов) это делается за два шага:

  1. Получите максимальное ценовое значение из таблицы с помощью SELECT.
  2. Используя это значение, надо создать фактический запрос:
    SELECT article, dealer, price FROM shop WHERE price=19.95
    

Другое решение состоит в том, чтобы сортировать все строки по убыванию цены и получить только первую из них, используя специфическое для MySQL предложение LIMIT:

SELECT article, dealer, price FROM shop ORDER BY price DESC LIMIT 1

ОБРАТИТЕ ВНИМАНИЕ: Если имеется несколько изделий с одинаковой ценой (например, каждое по 19.95), то LIMIT показывает только одно из них.

2.5.3 Максимум столбца в группе

Что является самой высокой ценой на изделие?

SELECT article, MAX(price) AS price FROM shop GROUP BY article
+---------+-------+
| article | price |
+---------+-------+
|    0001 |  3.99 |
|    0002 | 10.99 |
|    0003 |  1.69 |
|    0004 | 19.95 |
+---------+-------+

2.5.4 В какой строке максимум по группе

Для каждого изделия, найдите торгового агента с наиболее высокой ценой.

В ANSI SQL я сделал бы это подзапросом:

SELECT article, dealer, price FROM shop s1
       WHERE price=(SELECT MAX(s2.price) FROM shop s2
             WHERE s1.article = s2.article);

В MySQL проще всего добиться такого эффекта так:

  1. Получите список из записей (изделие, максимальная цена).
  2. Для каждого изделия получите из таблицы соответствующие строки, которые имеют максимальную цену.

Это может быть легко выполнено через временную таблицу:

CREATE TEMPORARY TABLE tmp (article INT(4) UNSIGNED ZEROFILL
       DEFAULT '0000' NOT NULL, price DOUBLE(16,2) DEFAULT '0.00'
       NOT NULL);
LOCK TABLES shop read;
INSERT INTO tmp SELECT article, MAX(price) FROM shop GROUP BY article;
SELECT shop.article, dealer, shop.price FROM shop, tmp
       WHERE shop.article=tmp.article AND shop.price=tmp.price;
UNLOCK TABLES;
DROP TABLE tmp;

Если Вы не используете таблицу TEMPORARY, Вы должны также блокировать таблицу tmp.

Можно это сделать одиночным запросом?

Да, но только используя совершенно неэффективный прием MAX-CONCAT trick:

SELECT article, SUBSTRING(MAX(CONCAT(LPAD(price,6,'0'),dealer)), 7)
       AS dealer, 0.00+LEFT(MAX(CONCAT(LPAD(price,6,'0'),dealer)), 6)
       AS price FROM shop GROUP BY article;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0001 | B      |  3.99 |
|    0002 | A      | 10.99 |
|    0003 | C      |  1.69 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

2.5.5 Применение переменных пользователя

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

Например, чтобы найти изделия с самыми высокими и низкими ценами, Вы можете сделать следующее:

select @min_price:=min(price),@max_price:=max(price) from shop;
select * from shop where price=@min_price or price=@max_price;
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0003 | D      |  1.25 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

2.5.6 Использование внешних ключей

Вы не нуждаетесь во внешних ключах, чтобы соединить 2 таблицы.

Единственная вещь, которую MySQL не делает, это CHECK, чтобы удостовериться, что ключи, которые Вы используете, действительно, существуют в таблице и автоматически не удаляет строки из таблицы с внешним ключом. Если Вы используете Ваши ключи обычным порядком, это только улучшит работу:

CREATE TABLE persons (id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
             name CHAR(60) NOT NULL, PRIMARY KEY (id));
CREATE TABLE shirts (id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
             style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
             color ENUM('red', 'blue', 'orange', 'white', 'black')
             NOT NULL, owner SMALLINT UNSIGNED NOT NULL REFERENCES persons,
             PRIMARY KEY (id));
INSERT INTO persons VALUES (NULL, 'Antonio Paz');
INSERT INTO shirts VALUES (NULL, 'polo', 'blue', LAST_INSERT_ID()),
   (NULL, 'dress', 'white', LAST_INSERT_ID()),
   (NULL, 't-shirt', 'blue', LAST_INSERT_ID());
INSERT INTO persons VALUES (NULL, 'Lilliana Angelovska');
INSERT INTO shirts VALUES (NULL, 'dress', 'orange', LAST_INSERT_ID()),
   (NULL, 'polo', 'red', LAST_INSERT_ID()),
   (NULL, 'dress', 'blue', LAST_INSERT_ID()),
   (NULL, 't-shirt', 'white', LAST_INSERT_ID());
SELECT * FROM persons;
+----+---------------------+
| id | name                |
+----+---------------------+
|  1 | Antonio Paz         |
|  2 | Lilliana Angelovska |
+----+---------------------+
SELECT * FROM shirts;
+----+---------+--------+-------+
| id | style   | color  | owner |
+----+---------+--------+-------+
|  1 | polo    | blue   |     1 |
|  2 | dress   | white  |     1 |
|  3 | t-shirt | blue   |     1 |
|  4 | dress   | orange |     2 |
|  5 | polo    | red    |     2 |
|  6 | dress   | blue   |     2 |
|  7 | t-shirt | white  |     2 |
+----+---------+--------+-------+
SELECT s.* FROM persons p, shirts s WHERE p.name LIKE 'Lilliana%'
       AND s.owner = p.id AND s.color <> 'white';
+----+-------+--------+-------+
| id | style | color  | owner |
+----+-------+--------+-------+
|  4 | dress | orange |     2 |
|  5 | polo  | red    |     2 |
|  6 | dress | blue   |     2 |
+----+-------+--------+-------+

2.5.7 Поиск на двух ключах

MySQL не оптимизирует запрос, когда Вы ищете на двух различных ключах, объединенных с помощью OR. Поиск на одном ключе с OR оптимизирован хорошо.

SELECT field1_index, field2_index FROM test_table WHERE field1_index = '1'
       OR field2_index = '1'

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

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

CREATE TEMPORARY TABLE tmp
SELECT field1_index, field2_index FROM test_table
       WHERE field1_index = '1';
INSERT INTO tmp
SELECT field1_index, field2_index FROM test_table
       WHERE field2_index = '1';
SELECT * from tmp;
DROP TABLE tmp;

Вышеупомянутый способ выполнить этот запрос в действительности вызывает UNION для двух запросов.

2.5.8 Вычисление посещений за день

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

CREATE TABLE t1 (year YEAR(4), month INT(2) UNSIGNED ZEROFILL,
       day INT(2) UNSIGNED ZEROFILL);
INSERT INTO t1 VALUES(2000,1,1),(2000,1,20),(2000,1,30),
       (2000,2,2),(2000,2,23),(2000,2,23);
SELECT year,month,BIT_COUNT(BIT_OR(1<<day)) AS days
       FROM t1 GROUP BY year,month;
+------+-------+------+
| year | month | days |
+------+-------+------+
| 2000 |    01 |    3 |
| 2000 |    02 |    2 |
+------+-------+------+

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

2.6 Использование mysql в пакетном режиме

В предыдущих разделах Вы использовали mysql в интерактивном режиме, чтобы ввести запросы и рассматривать результаты. Вы можете также выполнять mysql в пакетном режиме. Чтобы сделать это, поместите команды, Вы хотите выполнить в файл, затем сообщать, чтобы mysql читал ввод из файла:

shell> mysql < batch-file

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

shell> mysql -h host -u user -p < batch-file
Enter password: ********

Когда Вы используете mysql этим способом, Вы создаете файл скрипта, а затем выполняете скрипт.

Почему использование скриптов удобно? Имеется несколько причин:

Заданный по умолчанию выходной формат несколько иной (более краткий), когда Вы выполняете mysql в пакетном режиме. Например, вывод SELECT DISTINCT species FROM pet напоминает этот образец, когда выполнен в интерактивном режиме:

+---------+
| species |
+---------+
| bird    |
| cat     |
| dog     |
| hamster |
| snake   |
+---------+

Но когда выполнен в пакетном режиме, он подобен этому:

species
bird
cat
dog
hamster
snake

Если Вы хотите получать интерактивный выходной формат в пакетном режиме, используйте mysql -t. Для добавления к выводу команд, которые были выполнены, используется mysql -vvv.

2.7 Запросы из двух проектов

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

http://www.imm.ki.se/TWIN/TWINUKW.HTM

Последняя часть проекта управляется Web-интерфесом, написанным на Perl с базой данных под MySQL.

Каждую ночь (исследования ведутся днем) все данные из интервью перемещаются в базу данных MySQL.

2.7.1 Поиск всех важных близнецов

Следующий запрос используется, чтобы определить, кто из близнецов идет во вторую часть проекта:

select concat(p1.id, p1.tvab) + 0 as tvid,
       concat(p1.christian_name, " ", p1.surname) as Name,
       p1.postal_code as Code, p1.city as City, pg.abrev as Area,
       if(td.participation = "Aborted", "A", " ") as A,
       p1.dead as dead1, l.event as event1, td.suspect as tsuspect1,
       id.suspect as isuspect1, td.severe as tsevere1,
       id.severe as isevere1, p2.dead as dead2, l2.event as event2,
       h2.nurse as nurse2, h2.doctor as doctor2, td2.suspect as tsuspect2,
       id2.suspect as isuspect2, td2.severe as tsevere2,
       id2.severe as isevere2, l.finish_date from twin_project as tp
       left join twin_data as td on tp.id = td.id and tp.tvab = td.tvab
       left join informant_data as id on tp.id = id.id and tp.tvab=id.tvab
       left join harmony as h on tp.id = h.id and tp.tvab = h.tvab
       left join lentus as l on tp.id = l.id and tp.tvab = l.tvab
       left join twin_data as td2 on p2.id = td2.id and p2.tvab = td2.tvab
       left join informant_data as id2 on p2.id = id2.id and
       p2.tvab=id2.tvab left join harmony as h2 on p2.id = h2.id and
       p2.tvab = h2.tvab left join lentus as l2 on p2.id = l2.id and
       p2.tvab = l2.tvab, person_data as p1, person_data as p2,
       postal_groups as pg where p1.id = tp.id and p1.tvab = tp.tvab and
       p2.id = p1.id and p2.ptvab = p1.tvab and tp.survey_no = 5 and
       (p2.dead = 0 or p2.dead=9 or (p2.dead=1 and (p2.death_date=0 or
       (((to_days(p2.death_date)-to_days(p2.birthday))/365) >= 65))))
       and ((td.future_contact = 'Yes' and td.suspect = 2) or
       (td.future_contact = 'Yes' and td.suspect = 1 and id.suspect=1) or
       (ISNULL(td.suspect) and id.suspect=1 and id.future_contact='Yes') or
       (td.participation = 'Aborted' and id.suspect = 1 and
       id.future_contact = 'Yes') or (td.participation = 'Aborted' and
       ISNULL(id.suspect) and p2.dead = 0)) and l.event = 'Finished'
       and substring(p1.postal_code, 1, 2) = pg.code
       and (h.nurse is NULL or h.nurse=00 or h.doctor=00)
       and not (h.status = 'Refused' or h.status = 'Aborted'
       or h.status = 'Died' or h.status = 'Other') order by tvid;

Как Вам такой запрос? Даю некоторые объяснения:

concat(p1.id, p1.tvab) + 0 as tvid
Мы хотим сортировать на составном идентификаторе id и tvab в числовом порядке. Добавление 0 к результату заставляет MySQL обрабатывать его именно как число.
column id
Это идентифицирует пару близнецов. Это ключ во всех таблицах.
column tvab
Это идентифицирует близнецов в паре. Это имеет значение 1 или 2.
column ptvab
Это инверсия tvab. Когда tvab равно 1, ptvab принимает значение 2, и наоборот. Это существует, чтобы проще оптимизировать запрос.

Этот запрос показывает среди других вещей, как делать поиск на таблице из той же самой таблицы с объединением (p1 и p2). В примере это используется, чтобы проверить, умер ли партнер близнецов до 65 лет. Если так, строка не будет возвращена.

Все вышеприведенное существует во всех таблицах с информацией по близнецам. Мы имеем ключ на паре id,tvab (все таблицы) и другой паре id,ptvab (только в person_data), чтобы сделать запросы быстрее.

На нашей машине (200MHz UltraSPARC) этот запрос возвращает приблизительно 150-200 строк и требует времени меньше, чем одна секунда.

Текущее число записей в таблицах, используемых выше:
ТаблицаСтрок
person_data71074
lentus5291
twin_project5286
twin_data2012
informant_data663
harmony 381
postal_groups100

2.7.2 Состояние пары

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

select t1.event, t2.event, count(*) from lentus as t1, lentus as t2,
       twin_project as tp where t1.id = tp.id and t1.tvab=tp.tvab
       and t1.id = t2.id and tp.survey_no = 5 and t1.tvab='1' and
       t2.tvab='2' group by t1.event, t2.event;



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру