如何在PHP/MYSQL中将两个mysql查询作为一个查询执行?

29

我有两个查询,如下:

SELECT SQL_CALC_FOUND_ROWS Id, Name FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;
SELECT FOUND_ROWS();

我想一次执行这两个查询。

$result = mysql_query($query);

但是请告诉我如何单独处理每个表。 实际上在ASP.NET中,我们使用数据集(dataset) 来处理两个查询。

ds.Tables[0];
ds.Tables[1]; .. etc

如何使用PHP/MYSQL实现相同的功能?


可以使用CLIENT_MULTI_STATEMENTS标志实现这一点(请参见https://dev59.com/zXRA5IYBdhLWcg3w2xwI#28984274)。 - Pacerier
8个回答

32

更新:显然可以通过向mysql_connect()传递一个标志来实现。参见使用PHP在一个语句中执行多个SQL查询。然而,任何当前的读者都应避免使用mysql_类的函数,而应优先选择PDO。

在PHP中,你不能使用常规的mysql-api来做到这一点。只需执行两个查询。第二个查询将非常快,以至于不会有影响。这是一个典型的微优化示例。不要担心。

值得一提的是,可以使用mysqli和mysqli_multi_query函数来实现。


3
我主要关注性能问题,如果我们需要两次访问数据库的话,我认为性能会降低。 - djmzfKnm
1
如果您还不确定,请进行基准测试。执行SELECT FOUND_ROWS()查询并检索结果所需的时间是可以忽略不计的。您已经拥有连接,并且结果集非常小(只有一个整数)。 - Emil H
8
顺便说一下,如果您担心性能问题,您应该花时间尝试去除LIKE '%prashant%'语句。那可能是真正的性能问题。一般来说,大多数PHP应用程序的瓶颈不在于PHP本身,而是在于数据库。如果您想花时间优化应用程序,请花时间查看索引并解释查询。 - Emil H
我的第一个查询是插入数据,第二个查询是获取第一个查询插入的数据的 ID。由于记录被非常快速地插入到表中,运行 PHP 执行已经不是问题。 - AaA

8

像其他回答中提到的那样,mysqli API可以使用mysqli_multi_query()函数执行多个查询。

值得一提的是,PDO默认支持多个查询,并且您可以迭代多个查询的多个结果集:

$stmt = $dbh->prepare("
    select sql_calc_found_rows * from foo limit 1 ; 
    select found_rows()");
$stmt->execute();
do {
  while ($row = $stmt->fetch()) {
    print_r($row);
  }
} while ($stmt->nextRowset());

然而,出于安全原因,多查询通常被认为是一个不好的想法。如果您不小心构造查询字符串,您实际上可能会遭受到XKCD漫画中显示的确切类型的SQL注入漏洞,这是经典的“小博比表格”。当使用只限于单个查询的API时,这种情况是不会发生的。


4

如果您不想执行两次查询,那么您必须使用MySQLi扩展:

if (mysqli_multi_query($link, $query))
{
    $result1 = mysqli_store_result($link);
    $result2 = null;

    if (mysqli_more_results($link))
    {
        mysqli_next_result($link);
        $result2 = mysqli_store_result($link);
    }

    // do something with both result sets.

    if ($result1)
        mysqli_free_result($result1);

    if ($result2)
        mysqli_free_result($result2);
}

3

使用SQL_CALC_FOUND_ROWS是无法实现的。

通过FOUND_ROWS()可获取的行数是短暂的,并且不打算在SELECT SQL_CALC_FOUND_ROWS语句后继续存在。

正如之前有人在你的问题中提到的,使用SQL_CALC_FOUND_ROWS通常比仅仅获取计数更慢。

也许你最好将其作为子查询来处理:

SELECT 
 (select count(*) from my_table WHERE Name LIKE '%prashant%') 
as total_rows,
Id, Name FROM my_table WHERE Name LIKE '%prashant%' LIMIT 0, 10;

SQL_CALC_FOUND_ROWS虽然速度较慢,但在http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows链接中我发现“然而,这比不带LIMIT再次运行查询要快,因为结果集不需要发送到客户端。”? - djmzfKnm
1
但在这种情况下不行,因为该查询无法使用索引。SQL_CALC_FOUND_ROWS将导致单个表扫描,而您的子查询将导致两个表扫描,因此速度要慢得多。此外,在total_rows之后您忘记了逗号。 - Emil H
1
是的,好吧,你不能再次运行没有限制的查询。你正在运行一个count(*),它只发送一行。Emil H确实有一个很好的观点——这是一个值得怀疑的微优化。要么运行两个查询,要么如果你绝对必须这样做,就像我解释的那样将其作为子查询执行。(Emil H,感谢指出缺少逗号。) - tpdi

3

你需要使用MySQLi,以下代码可以正常工作

<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");

/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

$query  = "SELECT CURRENT_USER();";
$query .= "SELECT Name FROM City ORDER BY ID LIMIT 20, 5";

/* execute multi query */
if ($mysqli->multi_query($query)) {
    do {
        /* store first result set */
        if ($result = $mysqli->store_result()) {
            while ($row = $result->fetch_row()) {
                printf("%s\n", $row[0]);
            }
            $result->free();
        }
        /* print divider */
        if ($mysqli->more_results()) {
            printf("-----------------\n");
        }
    } while ($mysqli->next_result());
}

/* close connection */
$mysqli->close();
?>

1

像这样:

$result1 = mysql_query($query1);
$result2 = mysql_query($query2);

// do something with the 2 result sets...

if ($result1)
    mysql_free_result($result1);

if ($result2)
    mysql_free_result($result2);

1
他不想避免执行两次mysql_query吗? - Elazar Leibovich
1
是的,我想避免两次mysql查询。而在@Jon Benedicto的回答中,他执行了两个查询。 :( - djmzfKnm
我刚刚发布了另一个答案,展示如何使用MySQLi一次执行两个查询。 - Jon Benedicto

1

在 PHP 网站上说不允许使用多个查询(编辑:这只适用于 mysql 扩展。mysqli 和 PDO 允许多个查询)。所以你不能在 PHP 中这样做,但是,为什么不能在另一个 mysql_query 调用中执行该查询(就像 Jon 的示例一样)?如果您使用相同的连接,它仍然应该给您正确的结果。此外,mysql_num_rows 也可能有所帮助。


这仅适用于mysql扩展。mysqli和PDO允许多个查询。 - Ionuț G. Stan

0

是的,可以不使用MySQLi扩展实现。

只需在mysql_connect的第5个参数中使用CLIENT_MULTI_STATEMENTS即可。

有关更多信息,请参阅下面Husni's post的评论。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接