在准备好的语句中多次调用存储过程
我正在使用 PHP 处理从 Web 服务获取的一些 XML,并将结果插入到数据库中。我创建了一个存储过程来插入记录,并使用 PDO 准备一个语句,然后我想执行多次,如下所示:
$st = $this->db->prepare('CALL AddClient(:Name, :Id, :Priority, :Territory, :DateCreated, :Result)');
$st->bindParam(':Name', $Name, PDO::PARAM_STR);
$st->bindParam(':Id', $Id, PDO::PARAM_INT);
$st->bindParam(':Priority', $Priority, PDO::PARAM_STR);
$st->bindParam(':Territory', $Territory, PDO::PARAM_STR);
$st->bindParam(':DateCreated', $dateFormat, PDO::PARAM_STR);
$st->bindParam(':Result', $result, PDO::PARAM_STR);
foreach ($this->xml->AccountsDataSet->MainRecord as $Account) {
$Name = (string) $Account->AcctDesc;
$Id = (int) $Account->AcctID;
if ($num = (int)$Account->CDF309607) {
$Priority = self::$priorityFields[$num];
} else {
$Priority = '';
}
if (! $Territory = (string) $Account->AcctState) {
$Territory = '';
}
$date = new DateTime($Account->AcctCreationDate, new DateTimeZone('UTC'));
$dateFormat = $date->format('Y-m-d H:i:s');
$st->execute();
echo $result . '<br />';
}
在本例中,“:Result”将是来自程序。但我根本无法完成这项工作。如果我在过程代码和 PHP 中省略输出参数,则会插入一行,但循环中的后续调用会失败。为了完成这项工作,我必须在循环中每次都准备新鲜的语句,然后再次将参数绑定到该语句。我仍然无法使用过程中的输出参数来完成这项工作,并且必须在过程中选择一个值才能将一些返回值传递给 PHP 进行处理。
有谁知道我哪里出了问题?理想情况下,我想准备一次语句,然后循环遍历结果,每次都使用新数据执行它。为了让这一切顺利进行,我是否缺少任何技巧?我正在 Windows 7 上使用 Apache 2.2.17、PHP 5.3.5 和 MySQL 5.5.8 进行开发。
编辑: 那么,在循环中多次执行该语句的答案似乎是每次调用 PDOStatement::execute() 后都调用 PDOStatement::closeCursor() 方法。但仍然不知道如何获取返回给 PHP 的输出参数的值。
编辑 这是该过程的代码:
CREATE
PROCEDURE foo.AddClient(IN ClientName VARCHAR(255), IN Client_Id INT UNSIGNED, IN Priority VARCHAR(255), IN Territory VARCHAR(100), IN DateCreated DATETIME, OUT Result VARCHAR(100))
COMMENT 'Procedure to add a new client to the database'
BEGIN
#Declare variables.
DECLARE Priority_Id, Territory_Id TINYINT UNSIGNED DEFAULT NULL;
# Check if a Priority is defined. If so get the id, if not add it and get the id
IF LENGTH(Priority) > 0 THEN
SELECT
PriorityId
INTO
Priority_Id
FROM
client_priority
WHERE
Name = Priority;
IF Priority_Id IS NULL THEN
INSERT INTO client_priority (Name) VALUES (Priority);
SET Priority_Id = LAST_INSERT_ID();
END IF;
END IF;
#Check if a Territory is defined. If so get the id, if not add it and get the id.
IF LENGTH(Territory) > 0 THEN
SELECT
TerritoryId
INTO
Territory_Id
FROM
territories
WHERE
Name = Territory;
IF Territory_Id IS NULL THEN
INSERT INTO territories (Name) VALUES (Territory);
SET Territory_Id = LAST_INSERT_ID();
END IF;
END IF;
#Add the details of the client.
BEGIN
DECLARE EXIT HANDLER FOR SQLSTATE '23000'
SET Result = 'Client already exists'; # Error handler in case client with the same name already exists.
INSERT INTO clients
(ClientId, Name, PriorityId, TerritoryId, DateCreatedSalesNet) VALUES (Client_Id, ClientName, Priority_Id, Territory_Id, DateCreated);
SET Result = 'Client Inserted';
END;
END
I'm using PHP to process some XML that I'm getting from a web service and to insert the results into a database. I've created a stored procedure to insert the records and I'm using PDO to prepare a statement that I'd then like to execute multiple times, something like this:
$st = $this->db->prepare('CALL AddClient(:Name, :Id, :Priority, :Territory, :DateCreated, :Result)');
$st->bindParam(':Name', $Name, PDO::PARAM_STR);
$st->bindParam(':Id', $Id, PDO::PARAM_INT);
$st->bindParam(':Priority', $Priority, PDO::PARAM_STR);
$st->bindParam(':Territory', $Territory, PDO::PARAM_STR);
$st->bindParam(':DateCreated', $dateFormat, PDO::PARAM_STR);
$st->bindParam(':Result', $result, PDO::PARAM_STR);
foreach ($this->xml->AccountsDataSet->MainRecord as $Account) {
$Name = (string) $Account->AcctDesc;
$Id = (int) $Account->AcctID;
if ($num = (int)$Account->CDF309607) {
$Priority = self::$priorityFields[$num];
} else {
$Priority = '';
}
if (! $Territory = (string) $Account->AcctState) {
$Territory = '';
}
$date = new DateTime($Account->AcctCreationDate, new DateTimeZone('UTC'));
$dateFormat = $date->format('Y-m-d H:i:s');
$st->execute();
echo $result . '<br />';
}
In this example ':Result' would be a output value from the procedure. I cannot make this work at all though. If I omit the out put parameter both in the procedure code and PHP then one row gets inserted but subsequent calls in the loop fail. To make this work I have to prepare the statement fresh each time in the loop, then binding the parameters to the statement again. I still cannot make this work with an output parameter in the procedure and have to Select a value in the procedure to get some return value to PHP to process.
Does anyone know where I'm going wrong with this? Ideally I'd like to prepare the statement once and then loop through the results, executing it each time with fresh data. Are there any tricks that I'm missing to make all of this work? I'm developing on Windows 7 with Apache 2.2.17, PHP 5.3.5 and MySQL 5.5.8.
EDIT:
Well, the answer to executing the statement multiple times in the loop seems to be to call the PDOStatement::closeCursor() method each time after calling PDOStatement::execute(). Still no idea on how to get the value of an output parameter returned to PHP though.
EDIT
Here's the code for the procedure:
CREATE
PROCEDURE foo.AddClient(IN ClientName VARCHAR(255), IN Client_Id INT UNSIGNED, IN Priority VARCHAR(255), IN Territory VARCHAR(100), IN DateCreated DATETIME, OUT Result VARCHAR(100))
COMMENT 'Procedure to add a new client to the database'
BEGIN
#Declare variables.
DECLARE Priority_Id, Territory_Id TINYINT UNSIGNED DEFAULT NULL;
# Check if a Priority is defined. If so get the id, if not add it and get the id
IF LENGTH(Priority) > 0 THEN
SELECT
PriorityId
INTO
Priority_Id
FROM
client_priority
WHERE
Name = Priority;
IF Priority_Id IS NULL THEN
INSERT INTO client_priority (Name) VALUES (Priority);
SET Priority_Id = LAST_INSERT_ID();
END IF;
END IF;
#Check if a Territory is defined. If so get the id, if not add it and get the id.
IF LENGTH(Territory) > 0 THEN
SELECT
TerritoryId
INTO
Territory_Id
FROM
territories
WHERE
Name = Territory;
IF Territory_Id IS NULL THEN
INSERT INTO territories (Name) VALUES (Territory);
SET Territory_Id = LAST_INSERT_ID();
END IF;
END IF;
#Add the details of the client.
BEGIN
DECLARE EXIT HANDLER FOR SQLSTATE '23000'
SET Result = 'Client already exists'; # Error handler in case client with the same name already exists.
INSERT INTO clients
(ClientId, Name, PriorityId, TerritoryId, DateCreatedSalesNet) VALUES (Client_Id, ClientName, Priority_Id, Territory_Id, DateCreated);
SET Result = 'Client Inserted';
END;
END
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
事实上,您无法像这样访问结果,请参阅这些帖子:
所以你需要将结果存储到MySQL var中,然后你可以显示它,如下所示:
The fact is you can't access you result like this, see these posts :
So you will need to store the result into a MySQL var, then you can display it, like this :
尝试将字符串长度添加到输出参数:
Try adding a string length to the output parameter:
尝试添加 PDO::PARAM_INPUT_OUTPUT:
Try to add PDO::PARAM_INPUT_OUTPUT: