Программное создание запросов

Задача
Необходимо создать запрос INSERT или UPDATE из массива, составленного из имен полей. Например, требуется вставить нового пользователя в базу данных. Вместо того чтобы жестко запрограммировать каждое поле информации о пользователе (имя пользователя, почтовый адрес, дата рождения и т. д.), имена полей размещаются в массиве, и на основании этой информации и строится запрос. Так проще осуществлять поддержку, особенно если требуется, в зависимости от обстоятельств, выполнять запросы INSERT или UPDATE с одним и тем же набором полей.

Решение
Для выполнения запроса UPDATE постройте массив из пар поле/значение, а затем объедините все элементы этого массива с помощью функции join():

$fields = array('symbol','planet','element');
$update_fields = array();
foreach ($fields as $field) {
$update_fields[] = "$field = " . $dbh->quote($GLOBALS[$field]);
}
$sql = 'UPDATE zodiac SET ' . join(',',$update_fields)
. ' WHERE sign = ' . $dbh->quote($sign);

Для запроса INSERT создайте массив значений в порядке следования полей и постройте запрос, применяя функцию join() к каждому массиву:

$fields = array('symbol','planet','element');
$insert_values = array();
foreach ($fields as $field) {
$insert_values[] = $dbh->quote($GLOBALS[$field]);}
$sql = 'INSERT INTO zodiac (' .


join(',',$fields) . ') VALUES ('
. join(',',$insert_values) . ')';

Для PEAR DB версии 1.3 или старше следует применять метод DB::autoPrepare():
$fields = array('symbol','planet','element');
// UPDATE: вставьте выражение WHERE
$update_prh = $dbh->autoPrepare('zodiac',$fields,DB_AUTOQUERY_UPDATE,
'sign = ?');
$update_values = array();
foreach ($fields as $field) { $update_values[] = $GLOBALS[$field]; }
$update_values[] = $GLOBALS['sign'];
$dbh->execute($update_prh,$update_values);
// INSERT: без выражения WHERE
$insert_prh = $dbh->autoPrepare('zodiac',$fields,DB_AUTOQUERY_INSERT);
$insert_values = array();
foreach ($fields as $field) { $insert_values[] = $GLOBALS[$field]; }
$dbh->execute($insert_prh,$insert_values);

Обсуждение
В последних версиях DB метод DB::autoPrepare() короткий, и с ним легко работать. PHP 4.2.2 поставляется с версией DB 1.2. Самую свежую версию DB можно загрузить с PEAR. Функция method_exists() позволяет проверить, поддерживает ли ваша версия DB функцию autoPrepare():

if (method_exists($dbh,'autoPrepare')) {
$prh = $dbh->autoPrepare('zodiac',$fields,DB_AUTOQUERY_UPDATE',
'sign = ?');
// ...
} else {
error_log("Can't use autoPrepare");
exit;
}

Если функция DB::autoPrepare() недоступна, то можно прибегнуть к показанным в разделе «Решение» приемам обработки массивов, выполняющим ту же самую работу.


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

Функция определяет, существует ли запись, а затем генерирует корректный запрос, включая новый идентификатор, как показано в функции pc_build_query() примера 10.1.

Пример 10.1. pc_build_query()
function pc_build_query($dbh,$key_field,$fields,$table) {
if (! empty($_REQUEST[$key_field])) {
$update_fields = array();foreach ($fields as $field) {
$update_fields[] = "$field = ".$dbh->quote($_REQUEST[$field]);
}
return "UPDATE $table SET " . join(',',$update_fields) .
" WHERE $key_field = ".$_REQUEST[$key_field];
} else {
$insert_values = array();
foreach ($fields as $field) {
$insert_values[] = $dbh->quote($_REQUEST[$field]);
}
$next_id = $dbh->nextId($table);
return "INSERT INTO $table ($key_field," . join(',',$fields) .
") VALUES ($next_id," . join(',',$insert_values) . ')';
}
}

С помощью этой функции можно сделать простую страничку для редактирования всей информации из таблицы zodiac:

require 'DB.php';
$dbh = DB::connect('mysql://test:@localhost/test');
$dbh->setFetchMode(DB_FETCHMODE_OBJECT);
$fields = array('sign','symbol','planet','element',
'start_month','start_day','end_month','end_day');
switch ($_REQUEST['cmd']) {
case 'edit':
$row = $dbh->getRow('SELECT ' .


join(',',$fields) .
" FROM zodiac WHERE id = ?",array($_REQUEST['id']));
case 'add':
print '
';
print '';
print '';
if ('edit' == $_REQUEST['cmd']) {
printf('',
$_REQUEST['id']);
}
foreach ($fields as $field) {
if ('edit' == $_REQUEST['cmd']) {
$value = htmlspecialchars($row->$field);
} else {
$value = '';
}
printf('');
}
print '';
print '
%s: ,
$field,$field,$value);
printf('
';
break;
case 'save':$sql = pc_build_query($dbh,'id',$fields,'zodiac');
if (DB::isError($sth = $dbh->query($sql))) {
print "Couldn't add info: ".$sth->getMessage();
} else {
print "Added info.";
}
print '
';
default:
$sth = $dbh->query('SELECT id,sign FROM zodiac');
print '
    ';
    while ($row = $sth->fetchRow()) {
    printf('
  • %s',
    $_SERVER['PHP_SELF'],$row->id,$row->sign);
    }
    print '
  • Add New';
    print '
';
break;
}

Оператор switch на основе значения элемента $_REQUEST['cmd'] определяет, какое действие предпримет программа. Если $_REQUEST['cmd'] равен add или edit, то программа показывает текстовые окна для каждого поля из массива $fields, как показано на рис. 10.1. Если значение элемента $_REQUEST['cmd'] равно edit, то значения для строк с указанным $id загружаются из базы данных и отображаются в качестве значений по умолчанию. Если $_REQUEST['cmd'] равен save, то программа вызывает функцию pc_build_query(), чтобы сгенерировать соответствующий запрос на вставку или обновление информации в базе данных.

Определяя, какой запрос, INSERT или UPDATE, следует строить, функция pc_build_query() основывается на присутствии переменной запроса $_REQUEST['id'] (поскольку id передается в переменную $key_field). Если переменная $_REQUEST['id'] не пуста, то эта функция конструирует запрос UPDATE для модификации строки с указанным идентификатором. Если переменная $_REQUEST['id'] пуста (или она вовсе не была установлена), то функция генерирует новый идентификатор с помощью функции nextId() и использует этот новый идентификатор в запросе INSERT, который добавляет строку в таблицу.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела PHP на эту тему:
Автоматическое присваивание уникальных значений идентификаторов
Выполнение запросов к базе данных SQL
Извлечение строк без цикла
Кэширование запросов и результатов
Модификация данных в базе данных SQL

Вернуться в раздел: PHP / 10. Доступ к базам данных