Введение в MySQL (используя Perl DBI)
Перевод выполнил
Дмитрий Николаев. Оригинал на ангийском лежит здесь:
http://www.danchan.com/feature/2000/10/16/mysql/mysql.htm
Я считаю, что если название статьи не звучит для Вас чуждо,
то, возможно, Вы в нужном месте.
MySQL - это реляционная база данных. MySQL основана на технологии
client/server.
Все примеры команд MySQL в этой статье могут быть введены прямо в командную строку MySQL.
MySQL поддерживает многострочные команды и использует точку с запятой, как разделитель
между командами.
Почему же MySQL, а ни другая база данных SQL?
Хотя бы потому, что она бесплатна, быстра и
имеет хорошую поддержку.
Данные организуются как ряды и колонки,
образующие матрицу. С точки зрения SQL, матрица называется таблицей.
Лучший способ для C программиста понять что же это такое:
Каждый ряд - это структурная ссылка.
Каждая колонка - это член этой структуры.
Вот обычная структура (класс, объявленный с ключевым словом struct) в C:
struct users
{
int id;
char nickname[17];
char password[17];
int socks;
int favorite_number;
};
Это выглядит как информация, собранная Web-сайтом о пользователе.
А вот MySQL версия этой структуры:
create table users
(
id int auto_increment not null,
nickname varchar(16) not null,
password varchar(16) not null,
socks int,
favorite_number int,
primary key (user_id),
unique (nickname)
);
Несколько похоже, не так ли?
Вот как будет выглядеть ряд в MySQL:
+----+----------+----------+-------+-----------------+
| id | nickname | password | socks | favorite_number |
+----+----------+----------+-------+-----------------+
Что же тогда матрица? Вот данные в таблице(матрице) о трёх гипотетических
пользователях:
+----+----------+----------+-------+-----------------+
| 1 | GdayMate | dingo | 57 | 42 |
+----+----------+----------+-------+-----------------+
| 2 | Javier | cigar | 1 | 945 |
+----+----------+----------+-------+-----------------+
| 3 | Rolo | pudding | 9 | 8 |
+----+----------+----------+-------+-----------------+
Фактически эти таблицы - это то, что вы увидете, если введёте в MySQL следующую
команду:
select * from users;
Звёздочка означает, что мы выбираем все колонки из таблицы.
Таблица - это структурная основа многомиллиардной
годовой индустрии баз данных, которая включает в себя такие компании, как Oracle и Informix.
Простейшие команды MySQL
Давайте быстро "пробежим" по простейшим командам MySQL. Вы уже занете команду
create.
create table users
(
id int auto_increment not null,
nickname varchar(16) not null,
password varchar(16) not null,
socks int,
favorite_number int,
primary key (user_id),
unique (nickname)
);
А что же делать, если хотим увидеть только прозвища и любимые числа пользователей?
select nickname, favorite_number from users;
Данная команда даст нам:
+----------+-----------------+
| nickname | favorite_number |
+----------+-----------------+
| GdayMate | 42 |
+----------+-----------------+
| Javier | 945 |
+----------+-----------------+
| Rolo | 8 |
+----------+-----------------+
А если хотим вывести прозвища пользователей, но с условием, что носков у них меньше, чем
10 пар и их любимое число больше, чем 100?
select nickname from users where socks < 10 and favorite_number > 100;
+----------+
| nickname |
+----------+
| Javier |
+----------+
Как же ввести данные в таблицу?
Это просто.
insert into users (nickname, socks) values ('Cowlick', 0);
Да , но мы забыли добавить поле пароля в таблицу!
create table users
(
...
password varchar(16) not null,
...
);
Под NOT NULL понимается то, что
поле должно нести в себе какие-либо данные.
Поэтому в заданном выше примере MySQL выдаст ошибку.
Поэтому следует сделать так:
insert into users (nickname, password, socks) values ('Cowlick', 'udder', 0);
Результат будет следующим:
+----+----------+----------+-------+-----------------+
| id | nickname | password | socks | favorite_number |
+----+----------+----------+-------+-----------------+
| 4 | Cowlick | udder | 0 | NULL |
+----+----------+----------+-------+-----------------+
Но подождите! Мы не определили id! Оно также not
null.
create table users
(
id int auto_increment not null,
...
);
В этом случае колонку id
мы определили как auto_increment
и MySQL сама создаёт значения для нас, добавляя 1 к наибольшему значению, которое найдёт в таблице (Rolo имеет id == 3).
Мы забыли ввести любимое число пользователя Cowlick. Которое, между прочим,
-1. Для этого мы будем использовать команду update.
update users set favorite_number = -1 where id = 4;
Также можем выполнить это следующим образом:
update users set favorite_number = -1 where nickname = 'Cowlick';
Но вдруг у нас появится больше чем один пользователь с прозвищем
Cowlick?
В нашем примере этого быть не может, т.к. в командеcreate
table мы определили:
create tables users
(
...
unique (nickname)
);
Если мы попробуем ввести ещё одного пользователя с прозвищем Cowlick, то мы получим ошибку от MySQL.
Предположим Вы имеете проблемы с пользователем
Javier. Длугие члены вашего общества также считают, что
этому пользователю не место среди них, Вы можете сделать следующее
delete from users where nickname = 'Javier';
Если же Вы хотите удалить всю таблицу, то необходимо будет сделать следующее.
drop table users;
Определение таблицы и все данные после вышеописанной команды будут удалены. Будьте
осторожны с этой командой.
Типы MySQL и primary key
Мы не говорили о директиве primary
key в команде create table.
create table users
(
...
primary key (user_id),
...
)
Создаётся первичный ключ. Первичный ключ - это особый ключ, который может быть только
один для данной таблицы для каждой аблицы. По сути, первичный ключ - это уникальный (UNIQUE) ключ с именем
"PRIMARY". Несмотря на привелегированный статус, он функционирует как другой уникальный ключ. Но
select * from users where user_id = 2;
быстрее, чем
select * from users where favorite_number
= 945;
MySQL ограничен маленькими типами данных? Если, конечно, Вы считаете, что
4 гигабайта - это мало, то да. Это размер, который может быть помещён в поля типов LongBlob и LongText.
Предположим мы хотим создать форум. Простая таблица для хранения сообщений может
выглядеть так:
create table messages
(
id int auto_increment not null,
user_id int not null,
posting_date datetime not null,
comment_body text
primary key (id)
)
Этот пример предоставил нам два новых типа: datetime и text.
Данные колонки datetime структуированы
следующим образом: "YYYY-MM-DD hh:mm:ss".
В данном примере поdatetime могут быть отсортированы сообщения.
Для нас это всего лишь строка.
Типtextможет содержать данные до 64Kb,
что более чем достаточно для сообщения.
Колонка user_id является
реляционной частью Реляционной Системы Управления Базой Данных (РСУБД).
Вот пример ряда (message_body может быть более длинным):
+----+---------+---------------------+--------------+
| id | user_id | posting_date | message_body |
+----+---------+---------------------+--------------+
| 1 | 3 | 2000-10-10 10:00:00 | Wassup! |
+----+---------+---------------------+--------------+
Предположим мы имеем систему голосования,
где пользователи могут оценить действительно ли сообщение было достойно чтения
или нет. Создадим таблицу, подобную этой:
create table message_votes
(
message_id int not null,
user_id int not null,
vote enum('good', 'bad') not null,
primary key (message_id, user_id)
);
В этом примере колонка vote
может содержать одно из двух: либо 'good', либо 'bad'.
Для поиска голосования сообщения
можно будет сделать следующее:
select * from message_votes where message_id = 3;
, что будет быстрее, чем:
select * from message_votes where user_id = 2;
Но самым быстрым поиском голосования
по сообщению будет:
select * from message_votes where message_id = 3 and user_id = 2;
Теперь мы готовы к взаимодействию
DBI и MySQL.
Использование Perl DBI как интерфейс
для MySQL
Почему PERL? Почему не PHP? Как-никак,
но считается, что PHP4 достаточно быстр за счёт нового интерпретатора?
Я отвечу, потому, что Perl - это
язык, который наиболее часто сейчас используется. А я люблю идти в ногу со стандартами
индустрии. Perl имеет большую поддержку online и большинство книг написано о
нём. Существует CPAN, the Comprehensive Perl
Archive Network, где Вы можете найти модули для исполнения Ваших самых сокровенных
желаний, относительно программирования, конечно :-). DBI даёт Вам интерфейс,
который будет работать как с самой примитивной БД, так и с самой последней версией
Oracle РСУБД.
Давайте начнём с соединения с базой
данных:
use DBI;
my $dsn = 'DBI:mysql:my_database:localhost';
my $db_user_name = 'admin';
my $db_password = 'secret';
my ($id, $password);
my $dbh = DBI->connect($dsn, $db_user_name, $db_password);
Давайте предположим, что мы получили
из формы логин и пароль пользователя. Итак,
$input_nickname = 'Cowlick' и $input_password = 'udder'
Естественно наше желание проверить
действительно ли введёный пароль соответствует введёному логину в нашей БД.
my $sth = $dbh->prepare(qq{select id, password from users where nickname = $input_nickname});
$sth->execute();
Отмечу отсутствие точки с запятой.
При одной команде она не обязательна.
Как же мы получим результат? Т.к.
мы ожидаем всего один ряд то,
($id, $password) = $sth->fetchrow_array();
$sth->finish(): # закончили запрос
if ($input_password eq $password) # чувствительно к регистру
{
... # вход удачен
}
Что же делать если результат - более
одной строки? Продолжающиеся запросы к
$sth->fetchrow_array()
вернут нам оставшуюся часть данных.
my $sth = $dbh->prepare(qq{
select nickname, favorite_number from users
});
$sth->execute();
while (my ($nickname, $favorite_number) =
sth->fetchrow_array()) # делать выборку данных
# пока ничего не останется
{
print "$nickname, $favorite_number\n";
}
$sth->finish();
Если же мы хотим сохранить все результаты
для последующего использования
my (@matrix) = ();
while (my @ary = $sth->fetchrow_array())
{
push(@matrix, [@ary]); # [@ary] это ссылка
}
$sth->finish();
Ссылка для программистов на C может
быть расценена как указатель. Матрица теперь является массивом массивов
ссылок или же двумерным массивов ссылок.
Вы можете достать ряд $i
при помощи:
@{matrix[$i]}
Или, достать нужный ряд и колонку
($i, $j) в
таблице:
$matrix[$i][$j]
Для операций MySQL, которые не возвращают
результатов можно использовать метод do вместо prepare для того, чтобы выполнить SQL-команду.
$dbh->do("insert into message_votes
(message_id, user_id, vote) values (1, 3, 'good')");
И, наконец, чтобы окончить работу
с базой - рассоединение:
$dbh->disconnect();