Введение в MySQL (используя Perl DBI)

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_numbern"; 

} 

$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();