Выполнение нескольких SQL-запросов в одном выражении с помощью PHP
Кстати, лучше ли я делать mysql_close ($ db) после выполнения всех запросов?
Передайте 65536 в mysql_connect как 5-й параметр.
$conn = mysql_connect('localhost','username','password', true, 65536 /* here! */) or die("cannot connect"); mysql_select_db('database_name') or die("cannot use database"); mysql_query(" INSERT INTO table1 (field1,field2) VALUES(1,2); INSERT INTO table2 (field3,field4,field5) VALUES(3,4,5); DELETE FROM table3 WHERE field6 = 6; UPDATE table4 SET field7 = 7 WHERE field8 = 8; INSERT INTO table5 SELECT t6.field11, t6.field12, t7.field13 FROM table6 t6 INNER JOIN table7 t7 ON t7.field9 = t6.field10; -- etc ");
Когда вы работаете с mysql_fetch_ * или mysql_num_rows или mysql_affected_rows, действует только первый оператор.
Например, следующие коды, первый оператор INSERT, вы не можете выполнить mysql_num_rows и mysql_fetch_ *. Можно использовать mysql_affected_rows для возврата количества вставленных строк.
$conn = mysql_connect('localhost','username','password', true, 65536) or die("cannot connect"); mysql_select_db('database_name') or die("cannot use database"); mysql_query(" INSERT INTO table1 (field1,field2) VALUES(1,2); SELECT * FROM table2; ");
Другой пример: следующие коды, первый оператор – SELECT, вы не можете выполнить mysql_affected_rows. Но вы можете выполнить mysql_fetch_assoc, чтобы получить пару значений ключа из строки, полученную из первого оператора SELECT, или вы можете выполнить mysql_num_rows, чтобы получить количество строк на основе первого оператора SELECT.
$conn = mysql_connect('localhost','username','password', true, 65536) or die("cannot connect"); mysql_select_db('database_name') or die("cannot use database"); mysql_query(" SELECT * FROM table2; INSERT INTO table1 (field1,field2) VALUES(1,2); ");
Это может быть создано sql-инъекцией «SQL Injection Piggy-backed Queries». злоумышленники могут добавлять несколько вредоносных операторов sql. поэтому не добавляйте пользовательские входы непосредственно к запросам.
Вопросы безопасности
Функции API mysqli_query () и mysqli_real_query () не устанавливают флаг соединения, необходимый для активации нескольких запросов на сервере. Дополнительный вызов API используется для нескольких операторов, чтобы уменьшить вероятность случайных атак SQL-инъекций. Злоумышленник может попытаться добавить такие заявления, как; DROP DATABASE mysql или; SELECT SLEEP (999). Если злоумышленнику удается добавить SQL в строку оператора, но mysqli_multi_query не используется, сервер не будет выполнять второй, инъецированный и вредоносный SQL-оператор.
Вы можете просто добавить слово JOIN или добавить a; после каждой строки (как сказал @pictchubbate). Лучше это из-за удобочитаемости, и вы не должны мешать DELETE с INSERT; легко отправиться на юг.
Последний вопрос – вопрос дебатов, но, насколько я знаю, вы должны закрыть после набора запросов. Это относится в основном к старым простым mysql / php, а не PDO, mysqli. В этих случаях ситуация становится более сложной (и подогревается в дебатах).
Наконец, я бы предложил использовать PDO или какой-либо другой метод.
С mysqli вы можете использовать несколько операторов для реального использования mysqli_multi_query() .
Подробнее о нескольких операторах в Документах по PHP .
Php select несколько запросов
Suggested improvement(s) to example 1.
reasons:
Multi_query only returns a non false response if a data/result set is returned and only checks for the first query entered. Switching the first SELECT query with the INSERT query will result in a premature exit of the example with the message «Multi query failed: (0)».
The example assumes that once the first query doesn’t fail that the other queries have succeeded as well. Or rather it just exits without reporting that one of the queries after the first query failed seeing that if a query fails next_result returns false.
The changes in the example comes after the creation of the string $sql.
$mysqli = new mysqli ( «example.com» , «user» , «password» , «database» );
if ( $mysqli -> connect_errno ) echo «Failed to connect to MySQL: (» . $mysqli -> connect_errno . «) » . $mysqli -> connect_error ;
>
if (! $mysqli -> query ( «DROP TABLE IF EXISTS test» ) || ! $mysqli -> query ( «CREATE TABLE test(id INT)» )) echo «Table creation failed: (» . $mysqli -> errno . «) » . $mysqli -> error ;
>
$sql = «SELECT COUNT(*) AS _num FROM test; » ;
$sql .= «INSERT INTO test(id) VALUES (1); » ;
$sql .= «SELECT COUNT(*) AS _num FROM test; » ;
// changes to example 1 start here
// don’t bother checking the result from multi_query since it will return false
// if the first query does not return data even if the query itself succeeds.
$mysqli -> multi_query ( $sql );
do // while (true); // exit only on error or when there are no more queries to process
// check if query currently being processed hasn’t failed
if ( 0 !== $mysqli -> errno )
echo «Multi query failed: (» . $mysqli -> errno . «) » . $mysqli -> error ;
break;
>
// exit loop if there ar no more queries to process
if ( false === ( $mysqli -> more_results () )
break;
>
// get result of the next query to process
// don’t bother to check for success/failure of the result
// since at the start of the loop there is an error check &
// report block.
$mysqli -> next_result ()
> while ( true ); // exit only on error or when there are no more queries to process
?>
Note that the normal while ($mysqli->more_results() && $mysqli->next_result() has been replaced by two checks and while (true);
This is due to the ‘problem’ that next_result will return false if the query in question failed.
So one either needs to do one last check after the while loop to check if there was an error or one has to split up the different actions.
The changes in the example do the splitting.
Множественные запросы
MySQL поддерживает наличие нескольких SQL предложений в тексте одного запроса. Пересылка на сервер нескольких выражений в одном запроса уменьшает количество клиент-серверных взаимодействий, но требует специальной обработки.
Множественные запросы, или мультизапросы, должны запускаться функцией mysqli_multi_query() . Отдельные SQL предложения в мультизапросе отделяются точкой с запятой. После выполнения мультизапроса все результирующие наборы, которые он вернул, необходимо извлечь.
MySQL сервер поддерживает наличие в одном мультизапросе подзапросов, как возвращающих результирующий набор, так и не возвращающих.
Пример #1 Множественные запросы
$mysqli = new mysqli ( «example.com» , «user» , «password» , «database» );
if ( $mysqli -> connect_errno ) echo «Не удалось подключиться к MySQL: (» . $mysqli -> connect_errno . «) » . $mysqli -> connect_error ;
>
?php
if (! $mysqli -> query ( «DROP TABLE IF EXISTS test» ) || ! $mysqli -> query ( «CREATE TABLE test(id INT)» )) echo «Не удалось создать таблицу: (» . $mysqli -> errno . «) » . $mysqli -> error ;
>
$sql = «SELECT COUNT(*) AS _num FROM test; » ;
$sql .= «INSERT INTO test(id) VALUES (1); » ;
$sql .= «SELECT COUNT(*) AS _num FROM test; » ;
if (! $mysqli -> multi_query ( $sql )) echo «Не удалось выполнить мультизапрос: (» . $mysqli -> errno . «) » . $mysqli -> error ;
>
do if ( $res = $mysqli -> store_result ()) var_dump ( $res -> fetch_all ( MYSQLI_ASSOC ));
$res -> free ();
>
> while ( $mysqli -> more_results () && $mysqli -> next_result ());
?>
Результат выполнения данного примера:
array(1) < [0]=>array(1) < ["_num"]=>string(1) "0" > > array(1) < [0]=>array(1) < ["_num"]=>string(1) "1" > >
Рассмотрение аспектов безопасности
Функции API mysqli_query() и mysqli_real_query() во время работы не устанавливают на сервере специальный флаг, необходимый для выполнения мультизапросов. Отдельная API функция для мультизапросов позволяет снизить вероятность случайных SQL инъекций. Злоумышленник может попытаться добавить в конец запроса выражения, вроде ; DROP DATABASE mysql или ; SELECT SLEEP(999). Если ему это удастся, но не будет использоваться функция mysqli_multi_query, сервер не выполнит второе внедренное и опасное SQL выражение.
Пример #2 SQL инъекция
$mysqli = new mysqli ( «example.com» , «user» , «password» , «database» );
$res = $mysqli -> query ( «SELECT 1; DROP TABLE mysql.user» );
if (! $res ) echo «Ошибка при выполнении запроса: (» . $mysqli -> errno . «) » . $mysqli -> error ;
>
?>?php
Результат выполнения данного примера:
Ошибка при выполнении запроса: (1064) You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DROP TABLE mysql.user' at line 1
Использование множества выражений в подготавливаемом запросе не поддерживается.
- mysqli::query()
- mysqli::multi_query()
- mysqli_result::next-result()
- mysqli_result::more-results()