Рубрика «MySQL»

Обработка значения NULL

В синтаксисе SQL значение NULL занимает особое место - оно соответствует понятию “ничего”. Значение NULL не равно пустой строке или нулю, и эта особенность часто порождает ошибки. Рассмотрим несколько примеров:

SELECT NULL=FALSE;
SELECT NULL='';
SELECT NULL=0;
SELECT NULL=NULL;

NULL значения

Результатом всех запросов будет NULL. Это может выглядеть странно, но значение NULL не является значением в полном смысле слова: по определению оно означает отсутствие значения и не принадлежит ни одному типу данных. Поэтому NULL не равно ни логическому значению FALSE, ни пустой строке, ни нулю. При сравнении NULL с любым значением будет получен результат NULL, а не FALSE и не 0. Более того, NULL не равно NULL, и это иллюстрирует последний из приведенных запросов.

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

SELECT * FROM some_table WHERE some_column = NULL;
SELECT * FROM some_table WHERE some_column != NULL;

Такие запросы не вернут ни одной строки. Используйте запросы вида

SELECT * FROM some_table WHERE some_column IS NULL;
SELECT * FROM some_table WHERE some_column IS NOT NULL;

Восстановление разрушенных таблиц MySQL

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

CHECK TABLE messages;

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

В некоторых случаях в столбце Msg_text появляются сообщения об ошибках. В этом случае надо выполнить команду REPAIR TABLE, и MySQL предпримет попытку устранить проблему.

Утилита myisamchk, поставляемая с MySQL, позволяет проверять и восстанавливать таблицы MyISAM, обеспечивая при этом более высокую степень гибкости по сравнению с командами SQL. Если при запуске myisamchk не указаны опции, данная программа лишь проверяет таблицу на наличие ошибок. Ряд опций командной строки позволяют получить дополнительную информацию или указать утилите на то, что необходимо начать процесс восстановления данных.

Файлы с таблицами MyISAM, проверяемые утилитой myisamchk, находятся в каталоге, предназначенном для хранения данных, и имеют расширение .MYI. Если данные размещены в каталоге /var/lib/mysql, вы можете проверить все таблицы в базе forum с помощью команды:

myisamchk /var/lib/mysql/forum/*.MYI

Как правило, для быстрой проверки используется опция -fast. Она указывает на то, что проверке подлежат лишь те таблицы, которые были закрыты не корректно.

Опция –medium-check задает более детальную проверку таблиц, при которой могут быть найдены разнообразные ошибки. Самая тщательная проверка осуществляется при указании опции –extend-check, но она выполняется очень медленно. Данная опция используется только в том случае, если –medium-check не позволяет выявить проблему.

После того, как вы выяснили, что таблица разрушена, можно приступить к ее восстановлению. Для этой цели служит опция –recover. Перед тем как пытаться восстановить таблицу с помощью myisamchk, вам надо остановить mysqld. Если сервер выполнит запись в таблицу в то время, когда осуществляются действия по ее восстановлению, результаты могут быть непредсказуемыми.

В некоторых случаях программа myisamchk сообщает о том, что в данном режиме она не может устранить проблему, и вам необходимо задать опцию –safe-recover. При указании этой опции осуществляются дополнительные операции по восстановлению данных, но работа существенно замедляется.

Каталог продукции: сортировка + постраничная навигация

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

<?php
$dblocation = "localhost";   // Имя сервера
$dbuser     = "root";        // Имя пользователя
$dbpswrd    = "";            // Пароль
$dbname     = "products";    // Имя базы данных

DEFINE('ITEMS_PER_PAGE', 7);

// Соединение с сервером базы данных
$dblink = mysql_connect( $dblocation, $dbuser, $dbpswrd );
mysql_query( 'SET NAMES cp1251' );
// Выбираем базу данных
mysql_select_db( $dbname, $dblink );

// Выбираем из БД общее количество записей
$query = "SELECT COUNT(*) FROM products WHERE 1";
$res = mysql_query( $query );
$total = mysql_result( $res, 0, 0 );
   
// Проверяем передан ли номер текущей страницы (постраничная навигация)
if ( isset($_GET['page']) ) {
  $page = (int)$_GET['page'];
  if ( $page < 1 ) $page = 1;
} else {
  $page = 1;
}

$uri = $_SERVER['PHP_SELF'].'?';
if ( $_SERVER['QUERY_STRING'] != '' ) {
  foreach( $_GET as $key => $value ) {
    if ( $key != 'page' ) $uri = $uri.$key.'='.urlencode($value).'&';
  } 
}
// Сколько всего получится страниц
$cnt_pages = ceil( $total / ITEMS_PER_PAGE );
if ( $page > $cnt_pages ) $page = $cnt_pages;
// Начальная позиция
$start = ( $page - 1 ) * ITEMS_PER_PAGE;

// По умолчанию сортировка по наименованию, по возрастанию
$orderby = 'title';
$sort = 'ASC';
if ( isset( $_GET['orderby'] ) and isset( $_GET['sort'] ) ) {
  if ( in_array( $_GET['orderby'], array( 'code', 'title', 'price' ) ) ) $orderby = $_GET['orderby'];
  if ( in_array( $_GET['sort'], array( 'ASC', 'DESC' ) ) ) $sort = $_GET['sort'];
}

$query = 'SELECT code, title, description, price
          FROM products
          ORDER BY '
.$orderby.' '.$sort.'
          LIMIT '
.$start.', '.ITEMS_PER_PAGE;
$res = mysql_query( $query );

echo '<h1>Каталог продукции</h1>'."\n";
// Выводим "шапку" таблицы
echo '<table border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse; empty-cells: show;">'."\n";
echo '<tr>';
if ( $sort == 'ASC' ) {
  $tmp = 'DESC';
  $image = 'down.gif';
} else {
  $tmp = 'ASC';
  $image = 'up.gif';
}
if ( $orderby == 'code' )
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=code&sort='.$tmp.'&page='.$page.'">Код</a>&nbsp;<img src="'.$image.'" alt="" /></th>';
else
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=code&sort=ASC&page='.$page.'">Код</a></th>';
if ( $orderby == 'title' )
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=title&sort='.$tmp.'&page='.$page.'">Наименование</a>&nbsp;<img src="'.$image.'" alt="" /></th>';
else
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=title&sort=ASC&page='.$page.'">Наименование</a></th>';
echo '<th>Описание</th>';
if ( $orderby == 'price' )
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=price&sort='.$tmp.'&page='.$page.'">Цена</a>&nbsp;<img src="'.$image.'" alt="" /></th>';
else
  echo '<th><a href="'.$_SERVER['PHP_SELF'].'?orderby=price&sort=ASC&page='.$page.'">Цена</a></th>';
echo '</tr>'."\n";
while( $prd = mysql_fetch_array($res) ) {
  echo '<tr>';
  echo '<td>'.$prd['code'].'</td>';
  echo '<td>'.$prd['title'].'</td>';
  echo '<td>'.$prd['description'].'</td>';
  echo '<td>'.$prd['price'].'</td>';   
  echo '</tr>'."\n";
}
echo '</table>'."\n";

// Строим постраничную навигацию
if ( $cnt_pages > 1 )
{
    echo '<div style="margin:1em 0">&nbsp;Страницы: ';
    // Проверяем нужна ли стрелка "В начало"
    if ( $page > 3 )
        $startpage = '<a href="'.$uri.'page=1"><<</a> ... ';
    else
        $startpage = '';
    // Проверяем нужна ли стрелка "В конец"
    if ( $page < ($cnt_pages - 2) )
        $endpage = ' ... <a href="'.$uri.'page='.$cnt_pages.'">>></a>';
    else
        $endpage = '';

    // Находим две ближайшие станицы с обоих краев, если они есть
    if ( $page - 2 > 0 )
        $page2left = ' <a href="'.$uri.'page='.($page - 2).'">'.($page - 2).'</a> | ';
    else
        $page2left = '';
    if ( $page - 1 > 0 )
        $page1left = ' <a href="'.$uri.'page='.($page - 1).'">'.($page - 1).'</a> | ';
    else
        $page1left = '';
    if ( $page + 2 <= $cnt_pages )
        $page2right = ' | <a href="'.$uri.'page='.($page + 2).'">'.($page + 2).'</a>';
    else
        $page2right = '';
    if ( $page + 1 <= $cnt_pages )
        $page1right = ' | <a href="'.$uri.'page='.($page + 1).'">'.($page + 1).'</a>';
    else
        $page1right = '';

    // Выводим меню
    echo $startpage.$page2left.$page1left.'<strong>'.$page.'</strong>'.$page1right.$page2right.$endpage."\n";

    echo '</div>'."\n";
}
?>

Рабочий пример можно посмотреть здесь.