Xpoint
   [напомнить пароль]

Хранимые процедуры MySQL и PHP

Метки: [без меток]
2009-06-01 14:54:48 [обр] tcolonel[досье]

Всем привет, подскажите как вытаскивать результаты из хранимых процедур в PHP.

Пример:
CREATE TABLE `test` (
  `id` INTEGER(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(12) COLLATE cp1251_general_ci NOT NULL DEFAULT '',
  `hp` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0',
  `armor` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0',
  `grenade` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0',
  `bonus_time` DATETIME DEFAULT NULL,
  `active` TINYINT(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
)ENGINE=MyISAM
AUTO_INCREMENT=1 ROW_FORMAT=DYNAMIC
CHARACTER SET 'cp1251' COLLATE 'cp1251_general_ci'
COMMENT='';

CREATE PROCEDURE `my_test`(OUT id_out INT(11), name_in VARCHAR(12))
BEGIN
 SELECT id INTO id_out FROM test WHERE name = name_in AND active=1;
END

Пример взят отсюда

<?
 mysql_query("CALL my_test(@id, 'sergei')") or die("Couldn't CALL : " . mysql_error());
 mysql_query("SELECT @id") or die("Couldn't SELECT: " . mysql_error());
 $result = mysql_store_result($conn);
 $row = mysql_fetch_row($result);
 mysql_free_result($result);
 echo "<pre>"; print_r($row); echo "</pre>";
?>

Выдается ошибка: Couldn't CALL: Result consisted of more than one row - я
так понимаю что в результате несколько полей, так вот как их вытащить???

Спасибо.

спустя 2 часа 28 минут [обр] Евгений Седов aka KPbIC(7/176)[досье]
За вас погуглить?
спустя 1 минуту [обр] Thirteensmay(17/157)[досье]
Вы правильно понимаете что в результате получилось несколько полей, но вытащить их невозможно, т.к. эти несколько полей получились на этапе выполнения процедуры внутри БД, т.е. ошибка произошла внутри хранимой процедуры, результат к PHP даже не возвращался, вернулась только ошибка. Конструкция "SELECT id INTO id_out..." подразумевает что выберется только одна строка, это должно обеспечиваться условием where, тогда из этой одной выбранной строки выделиться одно поле и положиться в одну переменную id_out. Если SELECT выберет несколько строк то тогда полей id будет несколько, и положить их в одну переменную невозможно, именно такая ошибка у вас и произошла. PHP тут непричем. Вообще если вы собираетесь использовать хранимости в БД, то вы выбрали неудачную СУБД, MySQL плохо поддерживает хранимости. В частности она не позволяет нормально вернуть из процедуры набор данных (курсор), хотя извратиться можно, например создавать временную таблицу, сохранять результат процедуры в нее, а затем из приложения расчитывать эту таблицу. Также в документации написано что при использовании SELECT внутри хранимой процедуры, результат будет возвращен клиенту как обычно (при использовании интерфейса mysqli), но лично не пробовал ибо такой подход крайне убог в принципе.
спустя 3 часа 39 минут [обр] tcolonel[досье]

Евгений Седов aka KPbIC[досье]

сколько ни гуглил - ответа не нашел, зато вопросов с подобной проблемой встретил очень много ...

Thirteensmay[досье]

Спасибо за ответ. Я нашел еще упоминание о параметрах: CLIENT_MULTI_STATEMENTS и CLIENT_MULTI_RESULTS, только вот нигде не могу найти где их включать. Может Вы подскажите?

спустя 39 минут [обр] Евгений Седов aka KPbIC(7/176)[досье]
tcolonel[досье]
И Thirteensmay[досье] вам уже объяснил, и по первой ссылке, данной мной содержится ответ - A SELECT ... INTO должен возвращать не больше одной строки. (row - переводится как "строка", а не "столбец"). А ваш SELECT внутри хранимой процедуры возвращает больше одной строки, поэтому MySQL и ругается.
Какое слово, словосочетние или мысль из тех, что написал вам Thirteensmay[досье] или я, вызывает у вас затруднения в понимании?
спустя 2 часа 12 минут [обр] tcolonel[досье]
Евгений Седов aka KPbIC[досье]
Такое, что вот здесь написано совсем другое ...
спустя 7 часов [обр] Алексей Полушин(62/231)[досье]
tcolonel[досье]Ну здесь почитайте http://dev.mysql.com/doc/refman/5.0/en/select-into-statement.html
Обратите внимание - "The query should return a single row."
спустя 3 часа 21 минуту [обр] Thirteensmay(17/157)[досье]
tcolonel[досье] CLIENT_MULTI_STATEMENTS и CLIENT_MULTI_RESULTS можно включить при использовании C или MySQLi интерфейса. В представленном вами случае это не поможет, ошибка не в том что в PHP не передается набор, а в том что внутри хранимой процедуры вы результирующий набор хотите поместить в переменную которая может хранить только одно значение а не набор. В качестве кривого обходного варианта могу предложить внутри хранимой процедуры сделать цикл, который пройдется по всему результирующему набору вашего селекта, и все id сконкатенирует в одну строку через запятую, эту строку можно будет отдать на клиента и там рассплитовать.
спустя 37 минут [обр] Евгений Седов aka KPbIC(7/176)[досье]

tcolonel[досье]
Похоже, мы с вами используем разный диалект русского и английского языков. Проблема не в PHP, не в CALL, а в WHERE. У вас несколько (больше одной) строк в тестовой таблице удовлетворяют условию выборки. Вы мелко копнули. Если вы исполните ваш SELECT из CLI-клиента, то получите ту же самую ошибку.

Если вы хотите получить несколько id, вместо хранимой процедуры (вред которой в MySQL вам уже несколько раз объясняли) сделайте простую выборку. При работе с MySQL это будет правильное решение. При всем уважении к Thirteensmay[досье], хочу заметить, что использование предлагаемых им конструкций не расчитаны на ваш уровень.

Если же вам больше жизни нравятся хранимые процедуры, серьезно задумайтесь об использовании иной базы данных. Например Postgres

спустя 22 минуты [обр] Алексей Полушин(62/231)[досье]

А что, так в MySQL не работает ?

CREATE PROCEDURE `my_test`(name_in VARCHAR(12))
BEGIN
 SELECT id FROM test WHERE name = name_in AND active=1;
ENDПример взят отсюда

и

<?
 mysql_query("CALL my_test('sergei')") or die("Couldn't CALL : " . mysql_error());
 $result = mysql_store_result($conn);
 $row = mysql_fetch_row($result);
 mysql_free_result($result);
 echo "<pre>"; print_r($row); echo "</pre>";
?>
спустя 1 час 13 минут [обр] Thirteensmay(17/157)[досье]

Алексей Полушин[досье] Должно работать, я говорил об этом выше, но это imho не красиво (хак), и в перспективе при дальнейшем развитии MySQL может начать падать, хотя и не факт конечно.

tcolonel[досье] Если вы хотите освоить программирование СУБД с использованием хранимых процедур и прочих предоставляемых внутри сервера средств, то гораздо лучше это делать на основе полноценной в этом плане СУБД, а не сыро-недоделанной MySQL. Иначе вы не сможете нормально понять сути и прелести использования хранимостей, у вас сформируются превратные представления о них и вредные привычки, за все это вы заплатите страшным геморроем, ошибками и жестокими ограничениями, вам оно надо ? Рекомендую начать с Oracle, в частности с версии OracleХЕ, она бесплатна, прекрасно поддерживает хранимости и имеет кучу шикарной русской документации для новичков. Не обращайте внимания на некоторых личностей утверждающих будто Oracle сложный монстр, и в зад его, он конечно монстр, и может практически все, но это говорит лишь о том что у вас будет перспектива, начать изучение хранимостей на его основе несравненно лучше и легче чем на основе MySQL. Тут есть только один момент, Oracle все же коммерческая СУБД, и если вы дорастете до по настоящему больших проектов то придется платить деньги, но в вашей ситуации это не существенно. В принципе существует еще Postgres, он совсем бесплатен и имеет лицензию даже лучше чем у MySQL, он также лучше MySQL в плане хранимостей, однако не на много, и Ораклу уступает очень существенно.

спустя 30 минут [обр] Евгений Седов aka KPbIC(7/176)[досье]
Oracle vs Postgres.
Сейчас мы тут быстренько выясним, какая религия - истинная.
спустя 9 дней [обр] tcolonel[досье]
Thirteensmay[досье]
CLIENT_MULTI_STATEMENTS и CLIENT_MULTI_RESULTS можно включить при использовании C или MySQLi интерфейса. В представленном вами случае это не поможет, ошибка не в том что в PHP не передается набор, а в том что внутри хранимой процедуры вы результирующий набор хотите поместить в переменную которая может хранить только одно значение а не набор. В качестве кривого обходного варианта могу предложить внутри хранимой процедуры сделать цикл, который пройдется по всему результирующему набору вашего селекта, и все id сконкатенирует в одну строку через запятую, эту строку можно будет отдать на клиента и там рассплитовать.

Спасибо. Я в принципе почти так и сделал. )))

Евгений Седов aka KPbIC[досье]
Если же вам больше жизни нравятся хранимые процедуры, серьезно задумайтесь об использовании иной базы данных. Например Postgres

Спасибо за совет. Дело в том, что я не по своей прихоти использую MySQL. Есть некоторые моменты, из-за которых приходится это делать и пока от них нельзя избавиться.

Thirteensmay[досье]
Если вы хотите освоить программирование СУБД с использованием хранимых процедур и прочих предоставляемых внутри сервера средств, то гораздо лучше это делать на основе полноценной в этом плане СУБД, а не сыро-недоделанной MySQL. Иначе вы не сможете нормально понять сути и прелести использования хранимостей, у вас сформируются превратные представления о них и вредные привычки, за все это вы заплатите страшным геморроем, ошибками и жестокими ограничениями, вам оно надо ? Рекомендую начать с Oracle, в частности с версии OracleХЕ, она бесплатна, прекрасно поддерживает хранимости и имеет кучу шикарной русской документации для новичков. Не обращайте внимания на некоторых личностей утверждающих будто Oracle сложный монстр, и в зад его, он конечно монстр, и может практически все, но это говорит лишь о том что у вас будет перспектива, начать изучение хранимостей на его основе несравненно лучше и легче чем на основе MySQL. Тут есть только один момент, Oracle все же коммерческая СУБД, и если вы дорастете до по настоящему больших проектов то придется платить деньги, но в вашей ситуации это не существенно. В принципе существует еще Postgres, он совсем бесплатен и имеет лицензию даже лучше чем у MySQL, он также лучше MySQL в плане хранимостей, однако не на много, и Ораклу уступает очень существенно.

Спасибо за совет и ответ ) Я уже начал думать об этом ...

Powered by POEM™ Engine Copyright © 2002-2005