我有以下存储过程:
CREATE PROCEDURE `Get_Events_And_Deadlines_By_User`(IN `intervalStart` INT, IN `intervalEnd` INT)
BEGIN
IF (intervalStart != 0 AND intervalEnd != 0) THEN
SELECT 1 AS `test`;
ELSEIF (intervalStart != 0 AND intervalEnd = 0) THEN
BEGIN
SELECT 2 AS `test`;
IF ((SELECT FOUND_ROWS())=1) THEN
SELECT 3 AS `test`;
END IF;
END;
ELSE
SELECT 4 AS `test`;
END IF;
END
当我运行call Get_Events_And_Deadlines_By_User(1,0)
时,我只得到 2 的选择查询作为结果,if语句中的select永远不会返回。似乎只有在返回存储过程之前才会执行遇到的第一个选择查询。为什么是这样?我该怎么做才能解决这个问题?我希望选择查询INSIDE if if语句是if hold的唯一结果。
答案 0 :(得分:0)
您的程序会返回多个结果集 PDO:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly', array(
PDO::ATTR_EMULATE_PREPARES=>false,
PDO::MYSQL_ATTR_DIRECT_QUERY=>false,
PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
));
$result = $pdo->query('Call Get_Events_And_Deadlines_By_User(1,0)');
do {
foreach( $result as $row ) {
echo join(', ', $row), "\r\n";
}
echo "-----\r\n";
} while($result->nextRowset());
答案 1 :(得分:0)
我的测试:
mysql> DELIMITER $$
mysql> DROP PROCEDURE IF EXISTS `Get_Events_And_Deadlines_By_User`$$
Query OK, 0 rows affected, 1 warning (0,00 sec)
mysql> CREATE PROCEDURE `Get_Events_And_Deadlines_By_User`(
-> IN `intervalStart` INT,
-> IN `intervalEnd` INT
-> )
-> BEGIN
-> IF (intervalStart != 0 AND intervalEnd != 0) THEN
-> SELECT 1 AS `test`;
-> ELSEIF (intervalStart != 0 AND intervalEnd = 0) THEN
-> SELECT 2 AS `test`;
-> IF ((SELECT FOUND_ROWS())=1) THEN
-> SELECT 3 AS `test`;
-> END IF;
-> ELSE
-> SELECT 4 AS `test`;
-> END IF;
-> END$$
Query OK, 0 rows affected (0,00 sec)
mysql> DELIMITER ;
mysql> CALL `Get_Events_And_Deadlines_By_User`(1, 0);
+------+
| test |
+------+
| 2 |
+------+
1 row in set (0,00 sec)
+------+
| test |
+------+
| 3 |
+------+
1 row in set (0,00 sec)
Query OK, 0 rows affected (0,00 sec)
之后:Retrieving Multiple Result sets with stored procedure in php/mysqli。
答案 2 :(得分:0)
问: 我只获得带有2的select查询作为结果,if语句中的select永远不会返回。似乎只有在返回存储过程之前才会执行遇到的第一个选择查询。这是为什么?
A:该过程返回了第二个结果集。客户端负责请求第二个(和后续的)结果集。 (在PHP中,需要调用mysqli mysqli_next_result
或PDO nextRowset
函数,具体取决于您使用的接口库。
但这似乎不是你真正的问题。
问: 我该怎么做才能解决这个问题?
答:这实际上取决于您希望实现的行为。过程可以返回多个结果集,并且客户端可以处理它们。
问: 我想在if语句中将选择查询INSIDE作为唯一结果。
A:您希望运行查询(示例过程中的SELECT 2
查询),但您不希望该过程将其作为结果集返回。您只想知道查询返回多少行,并根据返回的行数有条件地控制存储程序中的流。
您可以使用几种结构来实现这一目标。可以在过程中运行查询而不用将该查询的结果作为结果集返回。
使用SELECT EXISTS (subquery)
我怀疑你真的不想使用FOUND_ROWS
功能;我怀疑你不想测试找到的行数是否完全等于1。
如果您尝试实现的是确定特定查询是否会返回一行或多行,则可以使用如下模式:
IF ( SELECT EXISTS ( SELECT 2 AS `test` ) ) THEN
SELECT 2 AS `test`;
ELSE
SELECT 3 AS `test`;
END IF;
鉴于示例代码中的查询保证只返回一行,我只是猜测你想要实现的目标。
如果您有查询,并且想要查看该查询是否返回一行,则可以将其包装在 EXISTS()
条件中,这将返回一个布尔值。
EXISTS(subquery)
返回值1;如果子查询没有返回一行,则返回0.
该构造可以在IF
内用于控制存储程序中的逻辑流程。
IF ( SELECT EXISTS(subquery) ) THEN
-- subquery returned at least one row, so do something
ELSE
-- subquery didn't return any rows, so do something else
END IF;
获取SELECT COUNT(1) INTO FROM (subquery) q
如果从子查询中测试行的“存在”是不够的;如果您需要获取子查询返回的完全行数,则可以使用COUNT()
聚合。例如:
SELECT COUNT(1) FROM (subquery) q
为避免将该查询的结果作为过程的结果集返回,您可以将其返回的值分配给过程变量或用户定义的变量。假设您已在过程顶部声明了一个过程变量,如下所示:
DECLARE myrowcount INT;
你可以这样做:
SELECT COUNT(1) INTO myrowcount FROM (subquery) q
IF ( myrowcount = 1 ) THEN
-- subquery returned exactly one row
ELSE
-- subquery either returned zero rows, or returned more than one row
END IF;
可以使用用户定义的变量代替过程变量。我的偏好是使用过程变量,如果不需要在执行过程之后保留那些行数。
(使用用户定义变量的最大缺点是它引入了不必要的模糊性。稍后读取代码的人会想知道在程序结束后是否确实需要存储在用户定义变量中的值。不知道这是程序的有目的,有意的副作用,还有其他依赖的东西。在我看来,避免这种歧义是使用程序变量的充分理由。)
答案 3 :(得分:0)
根据您在评论中提到的内容,我认为您正在寻找以下内容。我所做的只是将一个新参数作为输出添加到您的过程中,而不是使用SELECT
来填充test的值,我使用了从外部发送到您的函数的变量并从外部接收更新的值使用SELECT @test
来获取您的价值,而且一次只有一个值而不是两个。
如果您对我在程序中留下的评论有疑问,建议您详细了解FOUND_ROWS() usage。
DELIMITER $$
DROP PROCEDURE IF EXISTS `Get_Events_And_Deadlines_By_User` $$
CREATE PROCEDURE `Get_Events_And_Deadlines_By_User`(
IN `intervalStart` INT,
IN `intervalEnd` INT,
OUT `test` INT
)
BEGIN
IF (intervalStart != 0 AND intervalEnd != 0) THEN
SET test = 1;
ELSEIF (intervalStart != 0 AND intervalEnd = 0) THEN
BEGIN
SET test = 2;
# include your select query here,
# as you need if for FOUND_ROWS(), or
# it will always return 1 cause there is no successful
# SELECT query before it and it will be always 1.
SELECT * FROM someTable;
IF ((SELECT FOUND_ROWS())=1) THEN
SET test = 3;
END IF;
END;
ELSE
SET test = 4;
END IF;
END$$
DELIMITER ;
CALL Get_Events_And_Deadlines_By_User(1,0,@test);
SELECT @test;
我希望它有所帮助。