SQL (Статей: 7)

Работа с MySQLi

MySQLi - это улучшенный драйвер для работы с базами данных MySQL
Подробнее о драйвере вы можете прочитать в Википедии

Несколько примеров:

Инициализация базы данных
<?php
$mysqli = new mysqli('localhost','user','password','base');
if(!$mysqli) $mysqli->error;

Установка кодировки
<?php
$mysqli->set_charset('utf8');

Запрос в базу данных
<?php
//готовим запрос
$result = $mysqli->prepare("SELECT `col1`, `col2` FROM `table` WHERE `id`=?");
//вставляем параметры. 
//'i' - integer, 'd' - double или float, 's' - string
$result->bind_param('i', $_GET['id']);
//выполняем запрос
if($result->execute()){
    //подготавливаем переменные в которые будут занесены результаты
    $result->bind_result($col1, $col2);
    //заполняем переменные
    $result->fetch();
    //освобождаем память
    $result->close();
}else{
    //если запрос Не выполнился
    //выдаем ошибку
    die('error - '.$mysqli->errno.' - '.$mysqli->error);
}

Количество записей(1 вариант)
На примере предыдущего запроса
<?php
if($result->execute()){
    $count = $result->num_rows;
    $result->close();
}

Количество записей (2 вариант)
<?php
$result = $mysqli->prepare("SELECT COUNT(*) as `count` FROM `table`");
if($result->execute()){
    $result->bind_result($count);
    $result->fetch();
    $result->close();
}

Последний id insert
<?php
$result = $mysqli->prepare("INSERT INTO `table` (`col_1`,`col_2`) VALUES (?,?)");
$result->bind_param('is', $int_val, $string_val);
if($result->execute()){
    $last = $mysqli->insert_id;
    $result->close();
}

Чтобы упростить работу с бд можно создать пользовательскую функцию, например:
<?php
function db(){
    static $mysqli = null;
    if(!$mysqli){
        $mysqli = new mysqli('localhost','user','password','base');
        $mysqli->set_charset('utf8');
    }
    return $mysqli;
}

function prepare($val){
    return db()->prepare($val);
}

function otherUserFunc(){
    $data = prepare("SELECT `password` FROM `users` WHERE `id`=?");
    $data->bind_param('i', $_POST['id']);
    if($data->execute()){
        $data->bind_result($password);
        $data->fetch();
        $data->close();
    }
    if($password !== $_POST['password']){
        return false;
    }else{
        return true;
    }
}

Один совет! Откажитесь от "*" в запросе, доставайте только нужные данные, пример:
<?php
"SELECT `id`,`text` FROM `news` WHERE `id`=?";

Спасибо за внимание smile

CoolCMS
Настройки сервера

Начнем с глобальных настроек. В случае, если Web и MySQL сервера работают на одном компьютере (что обычно для небольших проектов), то имеет смысл заставить MySQL слушать (bind-address) только интерфейс локальной петли (127.0.0.1), или вообще работать через Unix сокеты(socket).
Это исключит возможность соединения с MySQL сервером потенциального злоумышленника. В случае, если MySQL-сервер и Web-сервер находятся на разных машинах, придется производить настройку брандмауэра, что мы не будем рассматривать в рамках этой статьи.
Также можно изменить стандартный порт соединения с MySQL сервером (port,в случае работы через TCP/IP) - это не сильно поможет против злоумышленника, который задался целью взлома, но очень затруднит работу всякого рода ботам.

bind-address = 127.0.0.1
socket = /var/run/mysqld/mysql.sock
port = 3307

Также следует упомянуть параметры, которые не относятся напрямую к MySQL серверу, но влияют на возможность соединения с ним PHP скриптов. Речь о параметрах default_host, default_user и default_password секции [MySQL] конфигурационного файла PHP (php.ini). Эти опции задают параметры по умолчанию для соединения скриптов с MySQL сервером. Т.е. при использовании этих опций, любой PHP скрипт сможет соединиться с базой данных без указания имени пользователя и пароля. Поэтому использовать эти параметры не рекомендуется.

Теперь перейдем к привилегиям базы данных

Установка привилегий базы данных

Доступ пользователей к базам данных MySQL сервера регламентируется привилегиями разного уровня. Информация о привилегиях хранится в базе данных mysql, в таблицах user, db, host, а также tables_priv и columns_priv.
Таблица user отвечает за пользователей и их глобальные привилегии (распространяются на все таблицы всех баз данных). Клиент (соединяющийся с БД пользователь) определяется полями Host (адрес узла клиента) и User(имя пользователя), т.е. для клиента с одним и тем же именем могут быть разные пароли и разные привилегии, в зависимости от того, с какого узла клиент соединяется с сервером баз данных. Можно также указать возможность соединения с любого хоста, но такого лучше не делать из соображений безопасности. Для каждой пары Host + User устанавливается пароль, хранящийся в поле Password в зашифрованном виде. Оставшиеся поля данной таблицы отвечают за предоставленные клиенту привилегии и доступные ресурсы сервера.

# Создание пользователя test_user для локального соединения с паролем test_passw
CREATE USER "test_user"@"localhost" IDENTIFIED BY "test_passw";
# Предоставление созданному пользователю глобальных привилегий на выборку,
# вставку, обновление и неограниченное количество ресурсов сервера
GRANT SELECT, INSERT, UPDATE ON * . * TO "test_user"@"localhost" 
    IDENTIFIED BY "test_passw" WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0
    MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;

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

# предоставление нашему пользователю test_user прав на выборку из БД test_db
GRANT SELECT ON `test_db`.* TO "test_user"@"localhost";

Таблица host задает задает права доступа для различных хостов к базе. Таблица по структуре похожа на вышеописанные.
И наконец, таблицы tables_priv и columns_priv отвечают за доступ к конкретной таблице базы или конкретному столбцу таблицы соответственно.

# предоставление пользователю прав на чтение столбцов col_1, col_1 
# из таблицы test_table базы данных test_db
GRANT SELECT (`col_1`, `col_2`) ON `test_db`.`test_table` TO "test_user"@"localhost"

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

Итак, подведем итоги.

- Никогда не используем настройки сервера по умолчанию (доходит до того, что некоторые инсталляции по умолчанию имеют пустой root пароль к серверу)
- Не устанавливаем параметры соединения с сервером в конфигурационных файлах PHP
- Никогда не используем пользователей с высоким уровнем привилегий в ваших скриптах, а тем более пользователя root
- Не позволяем (или сильно ограничиваем) возможность удаленного подключения к базе данных
- Для каждой базы создаем своего пользователя, который не имеет прав доступа к другим базам данных
- Разграничиваем пользователей, имеющих права на модификацию данных (INSERT, UPDATE, DELETE) и только на выборку (SELECT)
- У вас не должно быть пользователей, имеющих привилегии на работу со структурой базы данных или административных привилегий
- Соблюдение всех этих правил и рекомендаций не являются панацеей в плане безопасности, но позволяют в разы уменьшить уязвимость любого проекта.
mysql_affected_rows() Возвращает количество строк, измененных/удаленных/вставленных последним запросом UPDATE, DELETE или INSERT.
mysql_change_user() Переключает пользователя и базу данных для открытого соединения.
mysql_character_set_name() Возвращает название кодировки, установленной для данного соединения.
mysql_close() Закрывает соединение с сервером.
mysql_connect() Создает соединение с сервером баз данных MySQL. Данная функция не рекомендуется; вместо нее следует использовать функцию mysql_real_connect().
mysql_create_db() Создает базу данных. Данная функция не рекомендуется; вместо нее следует использовать команду SQL CREATE DATABASE.
mysql_data_seek() Ищет произвольную строку в результирующем наборе запроса.
mysql_debug() Выполняет отладочные операции DBUG_PUSH с заданной строкой.
mysql_drop_db() Удаляет базу данных. Эта функция не рекомендуется; вместо нее следует использовать команду SQL DROP DATABASE.
mysql_dump_debug_info() Заставляет сервер записывать отладочную информацию в журнал.
mysql_eof() Определяет, была ли данная строка последней из прочитанных в результирующем наборе данных. Эта функция не рекомендуется; mysql_errno() или mysql_error() могут быть использованы вместо нее.
mysql_errno() Возвращает номер ошибки для последней запущенной функции MySQL.
mysql_error() Возвращает сообщение об ошибке для последней запущенной функции MySQL.
mysql_escape_string() Экранирует специальные символы в строке, чтобы ее было возможно использовать в команде SQL.
mysql_fetch_field() Возвращает тип следующего поля таблицы.
mysql_fetch_field_direct() Возвращает тип поля таблицы по заданному номеру поля.
mysql_fetch_fields() Возвращает массив структур, содержащих информацию обо всех полях.
mysql_fetch_lengths() Возвращает массив длин всех столбцов в текущей строке.
mysql_fetch_row() Извлекает следующую строку из результирующего набора.
mysql_field_seek() Устанавливает курсор столбцов на заданный столбец.
mysql_field_count() Возвращает количество столбцов в результате для последнего запроса.
mysql_field_tell() Возвращает значение положения курсора поля для последнего вызова mysql_fetch_field().
mysql_free_result() Освобождает память, использованную для результирующего набора.
mysql_get_client_info() Возвращает информацию о версии клиента.
mysql_get_host_info() Возвращает строку, описывающую параметры текущего соединения.
mysql_get_proto_info() Возвращает версию протокола, используемого для данного соединения.
mysql_get_server_info() Возвращает номер версии сервера баз данных.
mysql_info() Возвращает информацию о последнем выполненном запросе.
mysql_init() Выделяет или инициализирует какую-либо структуру MYSQL.
mysql_insert_id() Возвращает идентификатор, сгенерированный для столбца AUTO_INCREMENT предыдущим запросом.
mysql_kill() Уничтожает заданный поток.
[b]mysql_list_dbs()
Возвращает имена баз данных, совпадающие с простым регулярным выражением.
mysql_list_fields() Возвращает имена полей, совпадающих с простым регулярным выражением.
mysql_list_processes() Возвращает список текущих потоков на сервере.
mysql_list_tables() Возвращает имена таблиц, совпадающих с простым регулярным выражением.
mysql_num_fields() Возвращает количество столбцов в результирующем наборе.
mysql_num_rows() Возвращает количество строк в результирующем наборе.
mysql_options() Устанавливает параметры соединения для mysql_connect().
mysql_ping() Проверяет, работает ли данное соединение с сервером, и восстанавливает соединение при необходимости.
[b]mysql_query()
Выполняет SQL-запрос, заданный в виде строки с нулевым символом в конце.
mysql_real_connect() Создает соединение с сервером баз данных MySQL.
[b]mysql_real_escape_string()
Экранирует специальные символы в строке, чтобы обеспечить возможность использования ее в команде SQL, с учетом установленной для данного соединения кодировки.
mysql_real_query() Выполняет SQL-запрос, заданный в виде фиксированной строки.
mysql_reload() Предписывает серверу перегрузить таблицы привилегий.
mysql_row_seek() Устанавливает курсор на заданную строку в результирующем наборе, используя величину, возвращенную из mysql_row_tell().
mysql_row_tell() Возвращает положение курсора строки.
mysql_select_db() Выбирает базу данных.
mysql_shutdown() Останавливает сервер баз данных.
mysql_stat() Возвращает информацию о текущем статусе сервера баз данных в виде строки.
[b]mysql_store_result()
Извлекает полный результирующий набор для данного клиента.
mysql_thread_id() Возвращает идентификатор текущего потока.
mysql_thread_safe() Возвращает 1, если клиенты скомпилированы как поддерживающие потоки.
mysql_use_result() Инициализирует построчное извлечение результирующего набора.



При подсоединения к серверу необходимо вызвать функцию mysql_init() для инициализации дескриптора соединения, затем с этим дескриптором вызвать функцию mysql_real_connect() (которая содержит такую информацию, как имя данного хоста, имя пользователя и пароль). После соединения функция mysql_real_connect() устанавливает флаг reconnect (часть данной структуры MYSQL) в значение 1. Этот флаг указывает, что в случае, если запрос не может быть выполнен из-за потери соединения, следует попытаться восстановить соединение с сервером до окончательного отказа от него. Для закрытия соединения вызывается функция mysql_close().

При активном соединении клиент может посылать SQL-запросы на сервер, используя функции mysql_query() или mysql_real_query(). Разница между этими двумя функциями состоит в том, что mysql_query() работает с запросом, представленным в виде строки с нулевыми окончаниями, в то время, как mysql_real_query() работает со строками фиксированной длины. Если данная строка содержит двоичные данные (которые могут состоять из нуля байтов), то необходимо использовать mysql_real_query().

Для каждого запроса без выборки данных (т.е. не вида SELECT, а, например, INSERT, UPDATE, DELETE) можно узнать количество измененных (затронутых) строк путем вызова функции mysql_affected_rows().

Для запросов SELECT можно извлечь выбранные строки как результирующий набор. (Следует учитывать, что некоторые команды сходны с SELECT в том смысле, что они тоже возвращают строки. Это команды SHOW, DESCRIBE и EXPLAIN. Они должны трактоваться тем же образом, что и команды SELECT.)

Для клиента существует два способа обработки результирующих наборов данных. Первый состоит в извлечении сразу всего результирующего набора целиком вызовом функции mysql_store_result(). Эта функция забирает с сервера все строки, возвращенные запросом, и хранит их в данном клиенте. Второй способ заключается в инициализации для клиента построчного извлечения результирующего набора путем вызова функции mysql_use_result(). Эта функция инициализирует указанное извлечение, но фактически не получает с сервера ни одной строки.

В обоих случаях доступ к строкам происходит с помощью функции mysql_fetch_row(). Совместно с mysql_store_result() mysql_fetch_row() осуществляет доступ к строкам, уже извлеченным с сервера. Совместно с mysql_use_result() mysql_fetch_row() реально получает данную строку с сервера. Информацию о размере данных в каждой строке можно получить вызовом функции mysql_fetch_lengths().

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

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

Преимущество функции mysql_store_result() состоит в том, что, поскольку все строки выбраны и находятся у клиента, то возможен не только последовательный доступ к строкам. В результирующем наборе данных можно перемещаться назад и вперед в, используя функции mysql_data_seek() или mysql_row_seek(), чтобы изменить положение текущей строки внутри результирующего набора. Можно также узнать количество находящихся в нем строк, вызвав функцию mysql_num_rows(). С другой стороны, для mysql_store_result() требования к памяти могут быть очень высокими для обширных результирующих наборов, что может привести к нехватке памяти.

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

Благодаря интерфейсу клиенты получают возможность соответствующим образом реагировать на запросы (извлекать строки только при необходимости) без уточнения, являлся или нет данный запрос выборкой. Это можно делать, вызывая функцию mysql_store_result() после каждого вызова mysql_query() (или mysql_real_query()). Если вызов результирующего набора был успешным, то данный запрос принадлежал к виду SELECT и можно производить чтение строк. Если вызов результирующего набора не удался, можно вызвать функцию mysql_field_count() для определения, можно ли было действительно ожидать результат. Если mysql_field_count() возвращает нуль, то данный запрос не возвратил никаких данных (это указывает, что запрос был вида INSERT, UPDATE, DELETE и т.д.), и не следовало ожидать возвращенных строк. Если функция mysql_field_count() является ненулевой, данный запрос должен был возвратить результат, но не сделал этого. Это указывает, что данный запрос был типа SELECT, но его выполнение оказалось неуспешным (см. пример в описании функции mysql_field_count()).

Как mysql_store_result() так и mysql_use_result() позволяют получить информацию о полях, составляющих результирующий набор (количество полей, их имена и типы и т.д.). Можно получить последовательный доступ к информации о полях внутри строки путем повторного вызова функции mysql_fetch_field() или к номеру поля внутри строки с помощью функции mysql_fetch_field_direct(). Текущее положение курсора поля может быть изменено вызовом функции mysql_field_seek(). Установка курсора производится последующим вызовом функции mysql_fetch_field(). Можно также получить информацию для всех полей сразу с помощью функции mysql_fetch_fields().

Для обнаружения ошибок и сообщения о них MySQL обеспечивает доступ к информации об ошибках посредством функций mysql_errno() и mysql_error(). Они возвращают код ошибки или сообщение об ошибке для последней запущенной функции (которая может быть успешной или не выполниться), позволяя определить место возникновения и характер ошибки.
Вступление
Никто точно не знает почему, но MySQL и PHP в большинстве web-проектов почти всегда используются вместе. Вроде разработчики PHP включили поддержку и других баз данных, да и MySQL можно использовать не только вместе с PHP. А может просто провайдеры стремясь снизить цену хостинга и привлечь клиентов, включали на серверах поддержку PHP и MySQL и это стало традицией?..

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

Данный класс не претендует на функциональную полноту, но как показывает многолетний опыт, свойств его хватает для многих проектов.
Что хочешь, то и получишь!

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

Ну например, если мы хотим узнать количество клиентов занесенных в базу данных>

SELECT COUNT(*) FROM `customers`;

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

Но как говориться, лучше один раз увидеть, чем сто раз услышать.

Забираем и смотрим класс
http://www.mysql.ru/docs/naumov/class.mysql.html

Ну а теперь посмотрим как этот зверь работает.

Шаг 1.

Откроем новую базу данных и создадим там пару таблиц.

CREATE DATABASE `test_mysql_class` ;

CREATE TABLE `customers` (
`customer_id` smallint(6) NOT NULL auto_increment,
`lastname` varchar(255) NOT NULL default '',
`surname` varchar(255) NOT NULL default '',
PRIMARY KEY (`customer_id`)
) TYPE=MyISAM AUTO_INCREMENT=4 ;

INSERT INTO `customers` VALUES (1, 'Pupkin', 'Vasya');
INSERT INTO `customers` VALUES (2, 'Mal4ish', 'Ploxish');
INSERT INTO `customers` VALUES (3, 'Mal4ish', 'Kibal4ish');


CREATE TABLE `orders` (
`customer_id` smallint(6) NOT NULL default '0',
`product_id` smallint(6) NOT NULL default '0',
KEY `customer_id` (`customer_id`,`product_id`)
) TYPE=MyISAM;

INSERT INTO `orders` VALUES (1, 12);
INSERT INTO `orders` VALUES (1, 23);
INSERT INTO `orders` VALUES (1, 34);
INSERT INTO `orders` VALUES (1, 65);
INSERT INTO `orders` VALUES (2, 12);
INSERT INTO `orders` VALUES (3, 33);
INSERT INTO `orders` VALUES (3, 43);
INSERT INTO `orders` VALUES (3, 655);
У нас появилось две таблицы, с клиентами и с их заказами.

Для теста хватит!

Шаг2.

Попытаемся соединиться с базой данных при помощи класса:
<?php
require("class.mysql.php");

$host = "localhost";
$only_db = "test_mysql_class";
$username = "username";
$password = "password";


$db = new mysql_db();

if(!$db->getConnect($host,$only_db,$username,$password)){
echo "Net contact :-(";
exit;
}else echo "Yes contact! ;-)
";

?>
Если у вас появилась надпись "Yes contact! ;-)", значит соединение с базой данных прошло успешно, можно переходить к изучению класса.

Внимание! Все примеры будут будут дописываться в конец первой программы!

Шаг 3.а

И так попробуем узнать, сколько у нас клиентов в базе данных?

<?php


$sql = "SELECT COUNT(*) FROM `customers` ";
$count = $db->query($sql, 1);
echo $count;
?>
Проще не бывает.

Класс проанализировал наш запрос, и понял, что на выход надо послать одно число. Если мы не хотим, что бы отладочная информация печаталась классом, то надо вместо:

$count = $db->query($sql, 1);
написать так:

$count = $db->query($sql, 0); или просто $count = $db->query($sql);
также это работает с MIN(*) и МАХ(*).

Шаг 3.б.

Теперь попробуем узнать какой id номер у нашего клиента, которого зовут Pupkin Vasya

<?php
...

$sql = "SELECT `customer_id` FROM `customers`";
$sql .= " WHERE `lastname` = 'Pupkin' AND `surname` = 'Vasya' LIMIT 0,1";
$customer_id = $db->query($sql, 1);
echo $customer_id;
?>
При „разборке“ этого выражения, класс „понял“, что на „гора“ надо выдать только одно число, а именно $customer_id . Почему? Потому, что во-первых мы делаем SELECT только по `customer_id` , a во-вторых и это самое главное, в конце $sql у нас стоит LIMIT 0,1 . Как говориться комментарии излишни.

Шаг 3.в.

Ну а теперь попробуем, найти имя и фамилию клиента зная его id.

<?php


$sql = "SELECT `lastname`,`surname` FROM `customers`";
$sql .= " WHERE `customer_id` = 1 LIMIT 0,1";
$obj = $db->query($sql, 1);
echo $obj;
?>
ну и что мы получим? Object

Да, мы получили обьект. Но у этого обьекта есть нужные нам свойства,
а именно `lastname` и `surname` ,а это то, что нам надо!

<?php
...

$sql = "SELECT `lastname`,`surname` FROM `customers`";
$sql .= " WHERE `customer_id` = 1 LIMIT 0,1";
$obj = $db->query($sql, 1);
echo $obj->lastname;
echo "
";
echo $obj->surname;
?>
Теперь мы получили:
Pupkin
Vasya
что нам и было надо!

Шаг 3.г.

А теперь мы захотим получить все имена клиентов из базы данных.

<?php
...

$sql = "SELECT `lastname`,`surname` FROM `customers` WHERE 1";
$array = $db->query($sql, 1);
echo $array;
?>
И что мы получили на выходе? Массив! Array

Но это массив обьектов, нам нужно только их перелистать и получить все имена!

<?php
...

$sql = "SELECT `lastname`,`surname` FROM `customers` WHERE 1";
$array = $db->query($sql, 1);
if(is_array($array))
foreach ($array as $obj)
echo $obj->lastname." ".$obj->surname."
";
?>
Вот они наши клиенты:

Pupkin Vasya
Mal4ish Ploxish
Mal4ish Kibal4ish
Шаг4.

Казалось бы всего перечисленного могло бы хватить, но... .

Если нам понадобиться получить все продукты которые заказали клиенты с фамилией Mal4ish ? Конечно проблем нет, так как MySQL не все вложенные SQL запросы поддерживает, то SQL запрос будет следующим:

SELECT `orders`.`product_id` AS id FROM ( `orders` LEFT JOIN `customers` ON `customers`.`customer_id` = `orders`.`customer_id`)WHERE `customers`.`lastname` = 'Mal4ish'

<?php
...

$sql = "SELECT `orders`.`product_id` AS id FROM ";
$sql .= "( `orders` LEFT JOIN `customers` ON `customers`.`customer_id` = `orders`.`customer_id`)";
$sql .= "WHERE `customers`.`lastname` = 'Mal4ish' ";
$array = $db->query($sql, 1);
if(is_array($array))
foreach ($array as $obj)
echo $obj->id."
";
?>
Но для некоторых это сложно и непонятно, а иногда такой запрос составить просто невозможно.

Что делать? Надо перевести комманды которые мы хотим выполнить в тот формат, который понимает MySQL.

Ну например SQL запрос можно было бы написать так:

SELECT `product_id` FROM `orders` WHERE `customer_id`
IN(SELECT `customer_id` FROM `customers` WHERE `lastname` = 'Mal4ish')
Только не пробуйте пропустить это через MySQL, конечно это не правильно.

Но если мы скажем нашему классу, что бы он разобрал эту конструкцию по частям и заменил то, что находится в скобках на реальные значения? Почему бы и нет? Но что бы избежать путаницы в настоящих и ненастоящих запросах, поставим в нашем примере вместо круглых, фигурные скобки, и пропустим в конце это через наш класс.
<?php
...

$sql = "SELECT `product_id` FROM `orders` WHERE `customer_id` IN";
$sql .= " {SELECT `customer_id` FROM `customers` WHERE `lastname` = 'Mal4ish' } ";
$array = $db->query($sql, 0);
if(is_array($array))
foreach ($array as $obj)
echo $obj->product_id."
";
?>
Если включить режим вывода на экран, то увидим, что наш класс меняет запрос который стоит в фигурных скобках, на результат разделенный запятой и снова выполняет запрос, пока не получит последний результат:

Yes contact! ;-)

---- SQL

SELECT `product_id` FROM `orders` WHERE `customer_id`
IN {SELECT `customer_id` FROM `customers` WHERE `lastname` = 'Mal4ish' }

---- IN SQL

SELECT `customer_id` FROM `customers` WHERE `lastname` = 'Mal4ish'


---- SQL

SELECT `product_id` FROM `orders` WHERE `customer_id` IN (2,3)

12
33
43
655
Результат совпадает с ожидаемым!

Источник:
http://www.mysql.ru/docs/naumov/
Всё что вы когда-либо хотели знать про mysql, php и кодировки, но боялись спросить! Почему кириллица на сайте отображается вопросами? Как правильно настроить сервер mysql для работы с кириллицей? Как поменять кодировку в mysql? Как изменить кодировку в скриптах php? Какую выбрать кодировку? Как сконвертировать базу данных из одной кодировки в другую? Эти и многие подобные вопросы с завидным упорством снова и снова поднимаются на различных форумах уже который год. В этом посте я постарался рассказать что нужно делать чтобы такие проблемы не возникали и дать наиболее эффективные советы на тот случай если они все-таки возникнут. Если вы не найдете ответ на свой вопрос здесь – напишите мне и я обязательно дополню этот текст с учетом вашего случая

Mysql, php и кодировки. Источник проблем.

Проблемы с кодировками в Mysql обусловлены историей создания этой программы. Так как разрабатывали mysql – европейцы – для них было естественно выбрать в качестве основной кодировки более удобную для себя latin1. Странно, но и по сей день большинство инсталляций Mysql по умолчанию работают с этой кодировкой что и создает для пользователей кириллицы проблемы с добавлением в базу данных строк на русском и украинском языках – в latin1 эти символы просто отсутствуют.

Поэтому первое что нужно сделать при возникновении проблем с кодировками в mysql – нужно проверить какая кодировка является для данной инсталляции mysql основной. Проверить это можно несколькими способами.
Настройка сервера mysql для нужной кодировки.
Если вы админ сервера или вы самостоятельно настраиваете собственную mysql на рабочей машине.
Откройте файл конфигурации mysql.ini (/etc/mysql.cnf для os linux) и найдите такие строки.

[mysqld]
default-character-set=название_кодировки
character-set-server=название_кодировки
init-connect="SET NAMES название_кодировки"
skip-character-set-client-handshake

Вместо “название_кодировки” нужно подставить название той кодировки, которую вы будете использовать. Для текстов на русском и украинском языках можно использовать utf8 или cp1251 (обратите внимание – названия кодировок в mysql пишутся без обычного дефиса!!!). Но я советовал бы использовать только utf8 – так вы себе сэкономите в будущем немало нервов.

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

Если у вас возникли проблемы с кодировкой на хостинге, где вы не имеете прав администратора, то проверить настройки кодировки для mysql вы сможете другим способом: установите соединение с mysql (при помощи консольной команды mysql или phpmyadmin – как вам удобнее) и выполните такой sql-запрос: show variables like ‘char%’. Этот запрос покажет вам значения переменных mysql, которые имеют отношение к кодировкам. Скорее всего, вы увидите что-то вроде такого
character_set_client latin1
character_set_connection latin1
character_set_database cp1251
character_set_filesystem binary
character_set_results latin1
character_set_server latin1
character_set_system utf8
character_sets_dir /usr/share/mysql/charsets/



Я специально привел выше пример НЕПРАВИЛЬНО НАСТРОЕННОГО СЕРВЕРА!!! Обратите внимание – в нем используются в разных случаях три(!) разные кодировки. Начинающему веб-программисту в такой ситуации будет сложно добиться корректной работы скрипта. Старайтесь чтобы все переменные были настроены на работу с одной и той же кодировкой. Тогда 99% проблем которые обсуждаются на форумах у вас просто не возникнут. Тут даже не столь важно какую именно кодировку вы выберете – главное чтобы она была везде одинаковой. Но все-таки старайтесь указывать в настройках ту кодировку, которую действительно будете использовать для хранения данных.

Итак, удачный вариант – это если команда show variables like ‘char%’ из абзаца выше покажет вам список одинаковых кодировок для каждой из переменных и еще лучше будет если эта кодировка совпадет с той которую используете вы.

Если же кодировка mysql отличается от вашей – не спешите расстраиваться. Изменить любую из этих переменных вы можете либо глобально, для всех правкой конфигов (если вы администратор сервера), либо только для себя – sql-запросом set character_set_database=utf8 (если вы пользователь). Такой запрос должен будет выполняться из вашего php скрипта сразу после установки соединения с сервером mysql. Ниже пример для установки кодировки utf8 из php скрипта.
mysql_query('SET character_set_database = utf8');
mysql_query('SET NAMES utf8');

Настройки для cp1251 выставляются аналогично.
mysql_query('SET character_set_database = cp1251');
mysql_query('SET NAMES cp1251');

Что касается character_set_database – постарайтесь сразу создать базу данных в нужной кодировке (как вариант – отправьте такую просьбу в техподдержку хостинга), тогда вы избежите по крайней мере одного лишнего запроса к mysql во время работы скрипта. Если удастся,то строчку с ‘character_set_database’ из приведенного выше кода можно будет удалить.
Примеры настроек сервера mysql для правильной работы с кодировками.

При правильно настроенном сервере делать запросы из скрипта для установки правильной кодировки уже будет не нужно.

Настройки для utf8
[mysqld]
default-character-set=utf8
character-set-server=utf8
collation-server=utf8_general_ci
init-connect="SET NAMES utf8"
skip-character-set-client-handshake

[mysqldump]
default-character-set=utf8

[client]
default-character-set = utf8

Настройки для cp1251
[mysqld]
default-character-set=cp1251
character-set-server=cp1251
collation-server=cp1251_general_ci
init-connect="SET NAMES cp1251"
skip-character-set-client-handshake

[mysqldump]
default-character-set=cp1251

[client]
default-character-set = cp1251
Проверка реальной кодировки в которой хранятся базы данных mysql.

В случае если вы все (и сервер, и php скрипт) настроили правильно, по инструкции выше, но русские буквы все равно не отображаются – проверьте действительно ли ваши строки сохранены в той кодировке, которую вы указали в настройках!!!

Простой способ проверки – сделайте дамп базы данных в sql-формате и откройте его в текстовом редакторе. Sql-формат – это обычный текст. Если ваша база данных mysql в кодировке cp1251 – открывайте в Блокноте. Если utf8 – в любом редакторе с поддержкой Юникода. Пролистайте файл и убедитесь что все надписи с кириллицей нормально читаются и что sql-команды create table и create database, которые встречаются в дампе содержат правильные названия кодировки mysql (той кодировки, которая вами была указана в настройках сервера или в запросах из php-скриптов.

Если кодировка не подходит – сделайте бекап базы на всякий случай, перекодируйте sql-дамп в любом текстовом перекодировщике, замените названия кодировок в файле на правильные и заливайте полученный файл на сервер mysql. Теперь с кодировками все должно быть в порядке smile
SQLite – это реляционная база данных, запросы к которой можно осуществлять при помощи языка запросов SQL. База данных не поддерживает все особенности SQL и уступает в функциональности другим развитым СУБД, но вполне подходит для хранения и извлечения информации.

Отличие SQLite от MySQL и аналогичных СУБД
Классические СУБД, такие как MySQL (а так же MS SQL, Oracle, PostgreeSQL) состоят из отдельного сервера, поддерживающего работу базы данных и прослушивающих определённый порт, на предмет обращения клиентов. В качестве клиента может выступать в том числе и расширение PHP, реализующего интерфейс, с помощью которого осуществляются запросы к базе. Движок SQLite и интерфейс к ней реализованы в одной библиотеке, что увеличивает скорость выполнения запросов. Такой сервер часто называют встроенным.

Замечание
Встроенный сервер имеется и у других баз данных, например, у MySQL, но его использование требует лицензионных отчислений, поэтому не получило широкое распространение в мире открытых исходных кодов.
SQLite является бестиповой базой данных. Точнее, есть только два типа – целочисленный "integer" и текстовый "text". Причём "integer" используется преимущественно для первичного ключа таблицы, а для остальных данных пойдёт "text". Длина строки, записываемой в текстовое поле, может быть любой.

Особенности SQLite
Все базы данных хранятся в файлах, по одному файлу на базу. Количество баз данных, а так же таблиц в них, ограниченно только свободным местом, имеющимся на сайте. А максимально возможный объём одной базы данных составляет 2 Тб.
Так как все данные хранятся в файлах, проблем с переносом базы данных с одного хостинга на другой не существует – достаточно лишь скопировать соответствующие файлы.

Установка SQLite
В PHP5 поддержка SQLite установлена и включена по умолчанию.
Установка под Windows: Для установки SQLite необходимо скачать и скопировать в папку с расширениями библиотеку "php_sqlite.dll", которую можно загрузить по ссылке: http://snaps.php.net/win32/PECL_STABLE/php_sqlite.dll. Затем необходимо раскомментировать (или добавить) строку "extension=php_sqlite.dll" в файле "php.ini". Для нормального функционирования SQLite также необходимо раскомментировать строку "extension=php_pdo.dll".

Замечание
Если используется полная версия PHP в zip-архиве, а не в виде инсталлятора, соответствующие библиотеки расширения должны находится в директории ext. Подробнее можно почитать в статье Установка Apache, PHP, MySQL.
Библиотека "php_pdo.dll" должна загружаться до загрузки "php_sqlite.dll". То есть в php.ini строка "extension=php_sqlite.dll" должна стоять после "extension=php_pdo.dll".
Установка под Unix: Скачайте свежую версию SQLite с официального сайта (http://sqlite.org/download.html). Прочтите файл "INSTALL", поставляемый с исходными тестами модуля. Или просто воспользуйтесь командой установки PEAR: "pear install sqlite".

Работа с SQLite
Создание базы данных: Для того чтобы создать новую базу данных необходимо воспользоваться функцией sqlite_open(). Если базы, имя которой указано в параметре "filename" не существует, то функция создаст новую базу данных с именем "filename" и вернёт идентификатор базы данных.
resource sqlite_open ( string filename [, int mode [, string &error_message]] )
В скрипте, преведённом ниже, демонстрируется создание новой базы данных:

<?php 
  // Создадим базу данных 
  $db = sqlite_open("my_database.db"); 
  if (!$db) exit("Не удалось создать базу данных!"); 
?>

В результате в папке со скриптом у нас появится файл с именем "my_database.db" – наша база данных.
Создание таблиц: Все запросы к базе данных выполняет функция sqlite_query(), которая имеет следующий синтаксис:
resource sqlite_query ( resource dbhandle, string query )

Замечание
Для работы с SQLite, как и любой реляционной базой данных используется язык запросов SQL. Поэтому создать таблицу данных можно при помощи традиционного запроса CREATE TABLE, вставить запись при помощи оператора INSERT, извлечь запись при помощи SELECT, а обновить существующую запись при помощи запроса UPDATE.

В приведённом ниже примере создаётся таблица table1, содержащая три поля: целочисленное поле id, которое выступает в качестве первичного ключа, и два текстовых поля field1 и field2.

<?php 
  // Создадим новую базу данных 
  $db = sqlite_open("my_database.db"); 
  if (!$db) exit("Невозможно создать базу данных!"); 
  // Создадим таблицу "table1" в базе 
  $query_table = sqlite_query($db, "CREATE TABLE table1 
                              (id INTEGER PRIMARY KEY, 
                              /* id автоматически станет автоинкрементным */ 
                               field1 TEXT, 
                               field2 TEXT); 
                              "); 
  if (!$query_table) exit("Невозможно создать таблицу в базе данных!"); 
  // Запишем что-нибудь в таблицу 
  $query_insert = sqlite_query($db, "INSERT INTO table1(field1, field2) VALUES ('PHP5', 'Apache');"); 
  if (!$query_insert) exit("Невозможно записать данные в таблицу!"); 
?>

После создания таблицы, в неё добавляется запись, содержащая строки 'PHP5' и 'Apache', поле id автоматически получает значение 1.

Вывод данных из базы: Для вывода данных из таблиц используется всё та же функция – sqlite_query(). Если выбирается несколько записей, результат выборки следует обработать при помощи цикла while() и функции sqlite_fetch_array(), которая имеет следующий синтаксис:
array sqlite_fetch_array ( resource result [, int result_type [, bool decode_binary]] )
Ниже приводится скрипт, демонстрирующий вывод нескольких записей из базы данных:

<?php 
  // Создадим новую базу данных 
  $db = sqlite_open("my_database.db"); 
  if (!$db) exit("Невозможно создать базу данных!"); 
  // Создадим таблицу "table1" в базе 
  $query_table = sqlite_query($db, "CREATE TABLE table1 
                              (id INTEGER PRIMARY KEY,  
                               /* id автоматически станет автоинкрементным */ 
                               field1 TEXT, 
                               field2 TEXT); 
                              "); 
  if (!$query_table) exit("Невозможно создать таблицу в базе данных!"); 
  // Запишем что-нибудь в таблицу 
  sqlite_query($db, "INSERT INTO table1(field1, field2) VALUES ('PHP5+', 'Apache');"); 
  sqlite_query($db, "INSERT INTO table1(field1, field2) VALUES ('SQLite – ', 'классная вещь');"); 
  sqlite_query($db, "INSERT INTO table1(field1, field2) VALUES ('Посетите ', 'sqlite.org');"); 
  // Сделаем выборку данных 
  $res = sqlite_query($db, "SELECT * FROM table1;"); 
  // В цикле выведем все полученные данные 
  while ($array = sqlite_fetch_array($res))  
  { 
    echo($array['field1'].$array['field2']." (id записи:".$array['id'].")<br />"); 
  } 
?>

В результате работы скрипта получим:
HP5+Apache (id записи:1) 
SQLite – классная вещь (id записи:2) 
посетите sqlite.org (id записи:3)

Редактрирование записи: Для изменения поля воспользуемся функцией sqlite_query() и передадим ей запрос на обновление (UPDATE).

<?php 
  // Создадим новую базу данных 
  $db = sqlite_open("my_database.db"); 
  if (!$db) exit("Невозможно создать базу данных!"); 
  // Создадим таблицу "table1" в базе 
  $query_table = sqlite_query($db, "CREATE TABLE table1 
                              (id INTEGER PRIMARY KEY,  
                               /* id автоматически станет автоинкрементным */ 
                               field1 TEXT, 
                               field2 TEXT); 
                              "); 
  if (!$query_table) exit("Невозможно создать таблицу в базе данных!"); 
  // Запишем что-нибудь в таблицу 
  sqlite_query($db, "INSERT INTO table1(field1, field2) VALUES ('PHP5+', 'Apache');"); 
  sqlite_query($db, "INSERT INTO table1(field1, field2) VALUES ('SQLite – ', 'классная вещь');"); 
  sqlite_query($db, "INSERT INTO table1(field1, field2) VALUES ('Посетите ', 'sqlite.org');"); 
  // Изменим поле с id=1 
  sqlite_query($db, "UPDATE table1 SET field2='Apache+Linux' WHERE id=1;"); 
  // Сделаем выборку данных 
  $query = sqlite_query($db, "SELECT * FROM table1;"); 
  // В цикле выведем все полученные данные 
  while ($array = sqlite_fetch_array($query))  
 { 
    echo($array['field1'].$array['field2']." (id записи:".$array['id'].")<br />"); 
  } 
?>

В результате получим:
PHP5+Apache+Linux (id записи:1) 
SQLite – классная вещь (id записи:2) 
посетите sqlite.org (id записи:3)
Удаление записи из таблицы: Чтобы удалить запись из таблицы, нужно передать функции sqlite_query() запрос на удаление (DELETE).

<?php 
  // Создадим новую базу данных 
  $db = sqlite_open("my_database.db"); 
  if (!$db) exit("Невозможно создать базу данных!"); 
  // Создадим таблицу "table1" в базе 
  $query_table = sqlite_query($db, "CREATE TABLE table1 
                              (id INTEGER PRIMARY KEY,  
                               /* id автоматически станет автоинкрементным */ 
                               field1 TEXT, 
                               field2 TEXT); 
                              "); 
  if (!$query_table) exit("Невозможно создать таблицу в базе данных!"); 
  // Запишем что-нибудь в таблицу 
  sqlite_query($db, "INSERT INTO table1(field1, field2) VALUES ('PHP5+', 'Apache');"); 
  sqlite_query($db, "INSERT INTO table1(field1, field2) VALUES ('SQLite – ', 'классная вещь');"); 
  sqlite_query($db, "INSERT INTO table1(field1, field2) VALUES ('Посетите ', 'sqlite.org');"); 
  // Удалим поле с id=2 
  sqlite_query($db, "DELETE FROM table1 WHERE id=2;"); 
  // Сделаем выборку данных 
  $query = sqlite_query($db, "SELECT * FROM table1;"); 
  // В цикле выведем все полученные данные 
  while ($array = sqlite_fetch_array($query))  
  { 
    echo($array['field1'].$array['field2']." (id записи:".$array['id'].")<br />"); 
  } 
?>

В результате получим:
PHP5+Apache (id записи:1) 
посетите sqlite.org (id записи:3)
Закрытие базы данных: Для закрытия базы данных используется функция sqlite_close(). В качестве единственного параметра функция принимает идентификатор открытой базы данных.
void sqlite_close ( resource dbhandle )

Схема использования данной функции представлена ниже
<?php 
  $db = sqlite_open("my_database.db"); 
  /* 
  ... Здесь происходит работа с БД ... 
  */ 
  sqlite_close($db); 
?>

Замечание
Закрывать базу данных данной функцией – необязательно. Все открытые базы данных автоматически закроются при завершении работы скрипта.
Автор - Гончаров А.Н.
Последние время надоело выполнять кучу запросов к базе и писать кучу кода,подсчёт результатов,проверка на существование,перегонять масcивы.Я решил написал class для удобной работы и сокращения кода.
Вот собственно небольшой класс
<?
/*
MySQL класс BY Орёл
icq: 952042
*/
/*Возвратит число*/
define('COUNT_NUM','countnum');
/*Возвратит запрос*/
define('QUERY','query');
/*Возвратит масив*/
define('ARRAY','array');
/*Возвратит асоцытивный масив*/
define('ASSOC','assoc');
/*Возвратит масив для Smarty цикла section*/
define('TEMPLATE','template');
/*Запрос с проверкой на существование ,возвращение true ,false*/
define('NUM_ROWS','numrows');
class sql_class{
function sql($query,$option){
if ($option == 'countnum'){
$OR_SELECT = mysql_result(mysql_query($query),0);
if (!$OR_SELECT) {$OR_SELECT = 0;}
return $OR_SELECT;
}elseif ($option == 'query'){
$OR_SELECT = mysql_query($query);
return $OR_SELECT;
}elseif ($option == 'array'){
$OR_SELECT = mysql_query($query);
$data = mysql_fetch_array($OR_SELECT);
return $data;
}elseif ($option == 'assoc'){
$OR_SELECT = mysql_query($query);
$data = mysql_fetch_assoc($OR_SELECT);
return $data;
}elseif ($option == 'template'){
$OR_SELECT = mysql_query($query);
while ($data = mysql_fetch_assoc($OR_SELECT)){
$dat[] = $data;
}
return $dat;
}elseif ($option == 'numrows'){
$OR_SELECT = mysql_query($query);
if (mysql_num_rows($OR_SELECT)){
return true;
}else{
return false;
}
}
}
function mysql_error(){
return mysql_error();
}
}
?>
Синтакси функции sql::sql()
sql(query,option)
query - Запрос в базу
option - Опция что вернуть
6 опций
COUNT_NUM - вернёт число mysql_result()
QUERY - вернёт запрос
ARRAY - вернёт масив с нумерацией
ASSOC - вернёт асоцитивный массив без нумерации полей ,но с именами
TEMPLATE - вернёт масив для шаблона Smarty
NUM_ROWS - выполнит проверку на существование и вернёт true или false
Ниже приведу примеру работы с классом.
Вызываем класс
<?
$s = new sql; // Достаточно один раз вызвать в шапке
?>
вызов функции
Пример-1 нам надо подсчитать количество записей в таблице с id 1
<?
$result = $s->sql("SELECT COUNT(*) FROM table WHERE id='1'",COUNT_NUM);
echo $result; // Результат
?>
Пример-2 выполнить и вернуть запрос
<?
$result = $s->sql("SELECT * FROM table WHERE id='1'",QUERY);
?>
Пример-3 сделать запрос и вернуть масив с именами полей и нумерацией.
<?
$result = $s->sql("SELECT * FROM table WHERE id='1'",ARRAY);
print_r($result); //Читаем массив
?>
Пример-4 получить асоцитивный масив без нумерации полей,но с именами
<?
$result = $s->sql("SELECT * FROM table WHERE id='1'",ASSOC);
print_r($result); //Читаем массив
?>
Пример-5 сделать запрос с выполнением подсчёта mysql_num_rows возвращение true или false
К примеру нам надо проверить существует ли в таблицы юзер с id 1
<?
$result = $s->sql("SELECT * FROM user WHERE id='1'",NUM_ROWS);
if ($result){
echo 'Пользователь существует';
}else{
echo 'Пользователь не существует';
}
?>
Пример-6 пример запроса и возвращение массива для шаблонизатора Smarty
<?
$result = $s->sql("SELECT * FROM user ",TEMPLATE);
?>

Вывод в шаблоне
{section name=i loop=$result}
{$result[i].name_pole}
{/section}
Для вывода ошибки запроса
echo $s->mysql_error();
Вроде всё smile .
Облако тегов / Авторы