MySQL存储过程仅返回一个选择查询

时间:2016-01-11 19:12:30

标签: php mysql sql stored-procedures

我有以下存储过程:

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的唯一结果。

4 个答案:

答案 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;

我希望它有所帮助。