Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

PHP5_nachinayushim

.pdf
Скачиваний:
29
Добавлен:
20.03.2015
Размер:
26.79 Mб
Скачать

424 Глава 10

Оператор сравнения

Описание

 

 

=

равно

!= or <>

не равно

<

меньше

>

больше

<=

меньше или равно

>=

больше или равно

 

 

Существует также нуль+безопасный оператор сравнения (<=>), который позволяет использовать значения равные или не равные NULL. Например:

mysql>

Select 1 <=> NULL;

+------------

 

+

| 1 =

NULL

|

+------------

 

+

|

NULL

|

+------------

 

+

С помощью логических операторов AND и OR можно указать множество условий:

mysql> SELECT usernumber, userid, userposition FROM user -> WHERE userposition = 'Utility Back'

-> OR userposition = 'Mid' -> AND usernumber < 5;

+------------

 

+--------

+--------------

 

+

| usernumber

| userid |

userposition |

+------------

 

+--------

+--------------

 

+

|

2

| Nicrot |

Mid

|

|

3

| Spargy |

Mid

|

|

6

| Greeny |

Utility back |

+------------

 

+--------

+--------------

 

+

3 rows in set (0.01 sec)

Однако полученные данные не совсем верные. Требовалось перечислить только строки, в которых значения поля usernumber не превышают 5, но последняя строка в результирующем множестве имеет значение usernumber равное 6. В чем причина? Все очень просто ++++++ оператор AND в данном случае применяется только к условию userposition='Mid'. Когда сервер выбирает записи об игроках Utility back, он не учитывает последнее условие, поэтому оператор AND не имеет смысла. Чтобы сгруппировать условия и определить приоритет операций сравнения, необходимо использовать круглые скобки, так же как и в PHP:

mysql> SELECT usernumber, userid, userposition FROM user

 

-> WHERE (userposition = 'Utility Back'

 

-> OR userposition = 'Mid')

 

 

-> AND usernumber < 5;

 

+------------

+--------

+---------------

+

| usernumber |

userid | userposition

|

+------------

+--------

+---------------

+

|

2 |

Nicrot | Mid

|

|

3 |

Spargy | Mid

|

+------------

+--------

+---------------

+

2

rows in set (0.47 sec)

 

Более подробная информация о MySQL+операторах приведена на Web+странице www.mysql.com/doc/en/Functions.html.

Получение данных от MySQL с помощью PHP 425

Упорядочение результатов

Чтобы отсортировать полученные строки данных по определенному полю, можно использовать предложение ORDER BY:

mysql> SELECT usernumber, userid, userposition FROM user

->

WHERE usernumber

< 5

ORDER BY userid;

+------------

 

+--------

 

+------------------

 

 

+

| usernumber |

userid |

userposition

|

+------------

 

+--------

 

+------------------

 

 

+

|

4

|

Dodge

|

Link

 

|

|

2

|

Nicrot |

Mid

 

|

|

1

|

Pads

|

Winger

|

|

3

|

Spargy |

Mid

 

|

+------------

 

+--------

 

+------------------

 

 

+

4

rows in set (0.05 sec)

 

 

 

При сортировке символьных полей MySQL упорядочивает их согласно ASCII*значениям, поэтому все прописные буквы помещаются перед строчными.

Предложение ORDER BY по умолчанию сортирует полученные значения в порядке по возрастанию, поэтому в предыдущем примере строки сортируются в алфавитном порядке по полю userid.

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

mysql> SELECT

userid FROM user ORDER BY userid DESC;

+-------------

+

| userid

|

+-------------

+

| Spargy

|

| Pads

|

| Nicrot

|

| Mac

|

| Greeny

|

| Dodge

|

+-------------

+

6 rows in set (0.03 sec)

Можно сортировать извлекаемые строки по нескольким полям, разделяя имена полей запятыми. В следующем примере данные сортируются по полю userposition (по возрастанию) и по полю userid (по убыванию):

mysql>

SELECT userid, username, userposition FROM user

->

WHERE userposition = 'Winger'

->

OR userposition = 'Mid'

->

ORDER BY userposition, userid DESC;

+---------

+------------------

+----------------

+

| userid

| username

| userposition

|

+---------

+------------------

+----------------

+

| Spargy

| Andrew Sparg

| Mid

|

| Nicrot

| Nic Malan

| Mid

|

| Pads

| Brian Reid

| Winger

|

| Mac

| Murray McCallum

| Winger

|

+---------

+------------------

+----------------

+

4 rows in

set (0.00 sec)

 

 

Не забывайте о том, что ORDER BY лучше всего работает с индексированными по+ лями, поскольку такие поля уже отсортированы.

426 Глава 10

Сравнение с образцом

С помощью операторов LIKE и NOT LIKE можно создавать образцы для выборки данных. Для этого используются следующие специальные символы:

% соответствует любой возможной строке, включая пустые строки (как * в ко+ мандах оболочки Unix или DOS);

_ соответствует любому одному символу (как ? в командах оболочки Unix или DOS).

Чтобы выбрать все строки, в которых значение поля useremail заканчивается подстрокой doggies_rugby.com, можно ввести следующий запрос:

mysql>

SELECT userid, username, userposition, useremail FROM user

 

->

WHERE useremail LIKE '%doggiesrugby.co.za'

 

 

->

ORDER BY username;

 

 

 

+--------

+------------------------

+--------------

+----------------------------

+

| userid | username

| userposition

| useremail

|

|--------

+------------------------

+--------------

+----------------------------

+

| Pads

| Brian Reid

| Winger

|tickyPads@doggiesrugby.co.za|

| Mac

| Murray McCallum

| Winger

|murray@doggiesrugby.co.za

|

+--------

+------------------------

+--------------

+----------------------------

+

2 rows

in set (0.49 sec)

 

 

 

Значения в полях типа TEXT нечувствительны к регистру символов. Если при сравнении необходимо учитывать регистр символов, то следует использовать поле типа BLOB.

Образец __c соответствует значению Mac в поле userid, тогда как образец __ со+ ответствует любой строке, состоящей в точности из двух символов. Вне зависимости от того, сколько символов _ имеется в образце, mysql пытается найти записи, имею+ щие точное количество символов:

mysql> SELECT userid FROM user WHERE userid LIKE '__c';

+--------

 

+

| userid

|

+--------

 

+

| Mac

|

+--------

 

+

1

row in set (0.00 sec)

Работа оператора NOT LIKE диаметрально противоположна. Ниже выбираются все записи, в которых значение поля userid не заканчивается на букву y:

mysql> SELECT userid FROM user

->

WHERE userid NOT LIKE '%y';

+----------+

| userid

|

+----------+

| Dodge

 

|

| Mac

 

|

| Nicrot

|

| Pads

 

|

+----------

 

+

4 rows in set (0.00 sec)

Кроме того, в MySQL можно использовать регулярные выражения. Однако эта тема выходит за рамки данной главы, более подробно регулярные выражения в MySQL описаны в документации на Web+странице www.mysql.com/doc/en/ Pattern_matching.html.

Получение данных от MySQL с помощью PHP 427

Получение итоговых данных

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

sum() выводит сумму значений заданного поля; max() выводит максимальное число в заданном поле; min() выводит минимальное число в заданном поле; avg() выводит среднее значение по заданному полю; count() выводит количество возвращаемых строк.

Например, используя функции min() и max(), можно получить минимальные и максимальные значения целочисленных полей:

mysql> SELECT min(usernumber), max(usernumber) FROM user;

+-----------------

 

+----------------------

+

| min(usernumber)

| max(usernumber)

|

+-----------------

 

+----------------------

+

|

1

6

|

|-----------------

 

+----------------------

+

1

row in set (0.00 sec)

 

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

count(имя_поля) подсчитывает только строки, в которых значение заданного поля не равно NULL;

count(*) подсчитывает все строки результирующего множества.

В следующем запросе с помощью функции count(*) определяется количество иг+ роков, имеющих номера (значения поля usernmuber) меньше 3:

mysql> SELECT count(*) FROM user WHERE usernumber < 3; +-----------+

| count(*)

|

+-----------+

|

2

|

+-----------+

1 row in set (0.00 sec)

Более сложные выборки

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

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

mysql> SELECT DISTINCT userid FROM access_log WHERE page LIKE '%.html'

->

 

ORDER BY userid;

 

+----------+

 

| userid

|

 

+----------+

 

| Brian

|

 

| Greeny

|

 

428 Глава 10

|

Nicrot

|

|

Pads

|

+----------+

4 rows in set (0.00 sec)

Можно применять функции группировки (min(), max(), count() и др.) для опре+ деленных групп записей, а не для всей базы данных. Например, для того чтобы под+ считать количество человек, которые играют в определенной позиции, можно сгруп+ пировать возвращаемые строки с помощью предложения GROUP BY:

mysql>

SELECT userposition, count(*) FROM user GROUP BY userposition

->

ORDER BY userposition DESC;

+--------------

 

+-----------

 

+

| userposition | count(*)

|

+--------------

 

+-----------

 

|

| Winger

|

2

|

| Utility back |

1

|

| Mid

 

|

2

|

| Link

 

|

1

|

+--------------

 

+-----------

 

+

4 rows

in set (0.00 sec)

 

 

Если использовать в одном запросе имена полей и функции группировки и не включить в запрос предложение GROUP BY, то будет сгенерирована ошибка:

mysql> SELECT userposition, count(*) FROM user ORDER BY userposition; ERROR 1140: Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP

columns is illegal if there is no GROUP BY clause

(ОШИБКА 1140: Смешивание GROUP-столбцов (MIN(),MAX(),COUNT() и т.д.)

с не GROUP-столбцами в случае отсутствия предложения GROUP BY не допускается)

Необходимо помнить о том, что предложение ORDER BY должно записываться в за+ просе последним (если запрос не ограничивается предложением LIMIT, которое долж+ но находиться в конце запроса), а предложение GROUP BY должно ему предшествовать.

Предположим, что последнюю таблицу требуется отсортировать по значениям во втором столбце, т.е. отсортировать ее строки по количеству игроков в каждой пози+ ции. Использовать count(*) в предложении ORDER BY нельзя, как же быть? Для та+ ких ситуаций в MySQL предусмотрено решение: псевдонимы. Псевдоним (alias) факти+ чески представляет собой новое имя для выражения, поля или даже таблицы. При указании в SELECT+операторе поля (или выражения) перед ним можно задать при+ сваиваемое ему обозначение: AS имя_псевдонима.

После этого результат вызова count(*) показывается в результирующем множе+ стве как поле с именем num_users. Более того, псевдоним можно интерпретировать как обычное поле и использовать его в предложении ORDER BY:

mysql>

SELECT userposition, count(*) AS num_users FROM user

->

GROUP BY userposition ORDER BY num_users;

+--------------

 

+-------------

 

+

| userposition | num_users

|

+--------------

 

+-------------

 

+

| Link

 

|

1

|

| Utility back |

1

|

| Mid

 

|

2

|

| Winger

|

2

|

+--------------

 

+-------------

 

+

4 rows

in set (0.00 sec)

 

 

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

mysql> SELECT userposition, count(*) AS num_users FROM user -> WHERE num_users > 1 GROUP BY userposition;

ERROR 1054: Unknown column 'num_users' in 'where clause'

(ОШИБКА 1054: Неизвестное имя поля 'num_users' в предложении 'where')

Получение данных от MySQL с помощью PHP 429

Однако возникает проблема ++++++ имя num_users не может быть определено до тех пор, пока не будет указано, как группировать записи. В то же время необходимо вве+ сти предложение WHERE до предложения GROUP BY, иначе возникнет синтаксическая ошибка. Решение в такой ситуации заключается в использовании предложения HAVING, которое позволяет указывать условие для столбца или псевдонима в конце оператора SELECT. Предложение HAVING используется так же, как и WHERE за исклю+ чением того, что оно помещается после предложения GROUP BY. Сервер выполняет данный запрос как и раньше, но прежде чем вернуть результирующее множество, он отбрасывает результаты, не соответствующие заданному условию:

mysql> SELECT userposition, count(*) AS num_users FROM user

 

-> GROUP BY userposition HAVING num_users > 1;

+--------------

 

+-----------

 

+

| userposition

| num_users |

+--------------

 

+-----------

 

+

| Mid

|

2

|

| Winger

|

2

|

+-------------

 

+------------

 

+

2

rows in set (0.00 sec)

 

 

Как извлечь данные из двух таблиц? Необходимо просто указать имена обеих таб+ лиц в предложении FROM:

mysql> SELECT username, page FROM user,

access_log

+---------------------

+-----------------

+

| username

| page

|

+---------------------

+-----------------

+

| Nic Malan

| /score.html

|

| Andrew Sparg

| /score.html

|

| Brian Reid

| /score.html

|

| Dave Mercer

| /score.html

|

| Murray McCallum

| /score.html

|

| Mark Greenfield

| /score.html

|

| Nic Malan

| /stats.html

|

| Andrew Sparg

| /stats.html

|

| Brian Reid

| /stats.html

|

| Dave Mercer

| /stats.html

|

...

 

 

...

 

 

| Mark Greenfield

| /log.html

|

| Nic Malan

| /penalties.html

|

| Andrew Sparg

| /penalties.html

|

| Brian Reid

| /penalties.html

|

| Dave Mercer

| /penalties.html

|

| Murray McCallum

| /penalties.html

|

| Mark Greenfield

| /penalties.html

|

+---------------------

+-----------------

+

60 rows in set (0.00 sec)

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

mysql> SELECT userid, page from user, access_log;

ERROR 1052: Column: 'userid' in field list is ambiguous (ОШИБКА 1052: Неоднозначное имя 'userid' в перечне полей)

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

430 Глава 10

поля полностью независимыми друг от друга. Устранить неоднозначность можно пу+ тем явного указания таблицы, из которой требуется выбрать значения данного поля. Для этого используется следующий синтаксис:

mysql> SELECT user.userid, page FROM user, access_log;

+------------

+-----------------

+

| userid

| page

|

+------------

+-----------------

+

| Dodge

| /score.html

|

| Greeny

| /score.html

|

| Mac

| /score.html

|

| Nicrot

| /score.html

|

| Pads

| /score.html

|

| Spargy

| /score.html

|

...

 

 

...

 

 

| Spargy

| /log.html

|

| Dodge

| /penalties.html |

| Greeny

| /penalties.html |

| Mac

| /penalties.html |

| Nicrot

| /penalties.html |

| Pads

| /penalties.html |

| Spargy

| /penalties.html |

+------------

+-----------------

+

60 rows in set (0.01 sec)

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

mysql> SELECT user.userid, page FROM user, access_log -> WHERE user.userid = access_log.userid;

+---------

+--------------------

+

| userid

| page

|

+---------

+--------------------

+

| Dodge

| /score.html

|

| Dodge

| /stats.html

|

| Greeny

| /log.html

|

| Greeny

| /penalties.html

|

| Mac

| /score.html

|

| Nicrot

| /log.html

|

| Nicrot

| /refs.html

|

| Pads

| /score.html

|

+---------

+--------------------

+

8 rows in set (0.00 sec)

В таких ситуациях отчетливо видна эффективность реляционных баз данных. Соз+ данная связь между записями данных в двух таблицах называется объединением (join) ++++++

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

По договору между издательством "Вильямс" и Интернет-Магазином "Books.Ru - Книги России" единственный легальный способ получения данного файла с книгой “PHP 5 для начинающих ” (ISBN 5-8459-1039-0) – покупка в Интернет-

магазине "Books.Ru - Книги России".

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

Получение данных от MySQL с помощью PHP 431

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

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

иеще раз практика. Используйте mysql+клиент для экспериментирования с запросами с различными типами полей ++++++ в конечном счете это единственный способ оценить возможности и сложности SQL+синтаксиса.

Практический пример сценария

Используя полученные навыки, можно создать сценарий для просмотра регистра+ ционных записей (назовем его userviewer.php), который использует таблицы базы данных sample_db и выполняет следующие функции:

подключается к базе данных sample_db, в которой находятся таблицы user

и access_log;

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

отображает ссылки с именами полей, которые можно использовать для сорти+ ровки списка пользователей по определенному полю в порядке по возрастанию или по убыванию;

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

На рис. 10.1 показан внешний вид интерфейса для этого сценария.

Рис. 10.1.

432 Глава 10

Для создания сценария просмотра базы данных потребуется два отдельных файла. Глобальные переменные и часто используемые функции помещаются в подключае+ мый файл common_db.inc, а бизнес+логика реализована в файле userviewer.php. Предполагается, что существует база данных sample_db, которая содержит таблицы user и access_log, причем в обеих таблицах имеются соответствующие данные.

Содержимое файла common_db.inc

В последующих разделах рассматривается каждый блок кода в файле common_db.inc.

Для краткости код функций db_connect() и sql_error() здесь не описывается. Они ничем не отличаются от одноименных функций, описанных в предыдущей главе.

Глобальные переменные

В данном сценарии придется использовать несколько переменных. Их объявления можно поместить в файл common_db.inc и обращаться к ним из сценария userviewer как к глобальным переменным (некоторые переменные, возможно, следует изменить, чтобы отразить параметры конкретной системы):

<?php

$dbhost = 'localhost'; $dbusername = 'phpuser'; $dbuserpassword = 'phppass'; $default_dbname = 'sample_db';

Определим количество записей отображаемых на странице по умолчанию (5):

$records_per_page = 5;

Укажем имена таблиц (user и access_log):

$user_tablename = 'user'; $access_log_tablename = 'access_log';

Определим переменные для хранения номера и описания ошибки:

$MYSQL_ERRNO = "; $MYSQL_ERROR = ";

Зададим размер нового окна браузера:

$new_win_width = 600; $new_win_height = 400;

Функция html_header()

Код функции html_header() представляет собой начало HTML+страницы и оп+ ределение JavaScript+функции open_window(), которую можно вызывать для откры+ тия нового окна при отображении подробной информации о пользователе:

function html_header() {

global $new_win_width, $new_win_height; ?>

<HTML>

<HEAD>

<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"> <!--

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]