10

我以前从未使用过 mysqli_multi_query ,这让我感到难以置信,我在网上找到的任何示例都无法帮助我弄清楚我想要做什么。

这是我的代码:

<?php

    $link = mysqli_connect("server", "user", "pass", "db");

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

    $agentsquery = "CREATE TEMPORARY TABLE LeaderBoard (
        `agent_name` varchar(20) NOT NULL,
        `job_number` int(5) NOT NULL,
        `job_value` decimal(3,1) NOT NULL,
        `points_value` decimal(8,2) NOT NULL
    );";
    $agentsquery .= "INSERT INTO LeaderBoard (`agent_name`, `job_number`, `job_value`, `points_value`) SELECT agent_name, job_number, job_value, points_value FROM jobs WHERE YEAR(booked_date) = $current_year && WEEKOFYEAR(booked_date) = $weeknum;";
    $agentsquery .= "INSERT INTO LeaderBoard (`agent_name`) SELECT DISTINCT agent_name FROM apps WHERE YEAR(booked_date) = $current_year && WEEKOFYEAR(booked_date) = $weeknum;";
    $agentsquery .= "SELECT agent_name, SUM(job_value), SUM(points_value) FROM leaderboard GROUP BY agent_name ORDER BY SUM(points_value) DESC";

    $i = 0;
    $agentsresult = mysqli_multi_query($link, $agentsquery);

    while ($row = mysqli_fetch_array($agentsresult)){
        $number_of_apps = getAgentAppsWeek($row['agent_name'],$weeknum,$current_year);
        $i++;
?>

            <tr class="tr<?php echo ($i & 1) ?>">
                <td style="font-weight: bold;"><?php echo $row['agent_name'] ?></td>
                <td><?php echo $row['SUM(job_value)'] ?></td>
                <td><?php echo $row['SUM(points_value)'] ?></td>
                <td><?php echo $number_of_apps; ?></td>
            </tr>

<?php

    }
?>

我要做的就是运行多个查询,然后使用这 4 个查询的最终结果并将它们放入我的表中。

上面的代码根本不起作用,我只是收到以下错误:

警告:mysqli_fetch_array() 期望参数 1 为 mysqli_result,布尔值在 C:\xampp\htdocs\hydroboard\hydro_reporting_2010.php 第 391 行给出

有什么帮助吗?

4

6 回答 6

8

手册mysqli_multi_query()返回bool指示成功。

要从第一个查询中检索结果集,您可以使用 mysqli_use_result() 或 mysqli_store_result()。所有后续查询结果都可以使用 mysqli_more_results() 和 mysqli_next_result() 处理。

这是一个返回多查询最后一个结果的函数:

function mysqli_last_result($link) {
    while (mysqli_more_results($link)) {
        mysqli_use_result($link); 
        mysqli_next_result($link);
    }
    return mysqli_store_result($link);
}

用法:

$link = mysqli_connect();

$query  = "SELECT 1;";
$query .= "SELECT 2;";
$query .= "SELECT 3";

mysqli_multi_query($link, $query);
$result = mysqli_last_result($link);
$row = $result->fetch_row();
echo $row[0];  // prints "3"

$result->free();
mysqli_close($link);
于 2011-01-12T10:22:45.177 回答
4

好的,经过一番摆弄,反复试验并参考我在谷歌搜索中遇到的另一篇文章,我已经设法解决了我的问题!

这是新代码:

<?php

    $link = mysqli_connect("server", "user", "pass", "db");

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

    $agentsquery = "CREATE TEMPORARY TABLE LeaderBoard (
        `agent_name` varchar(20) NOT NULL,
        `job_number` int(5) NOT NULL,
        `job_value` decimal(3,1) NOT NULL,
        `points_value` decimal(8,2) NOT NULL
    );";
    $agentsquery .= "INSERT INTO LeaderBoard (`agent_name`, `job_number`, `job_value`, `points_value`) SELECT agent_name, job_number, job_value, points_value FROM jobs WHERE YEAR(booked_date) = $current_year && WEEKOFYEAR(booked_date) = $weeknum;";
    $agentsquery .= "INSERT INTO LeaderBoard (`agent_name`) SELECT DISTINCT agent_name FROM apps WHERE YEAR(booked_date) = $current_year && WEEKOFYEAR(booked_date) = $weeknum;";
    $agentsquery .= "SELECT agent_name, SUM(job_value), SUM(points_value) FROM leaderboard GROUP BY agent_name ORDER BY SUM(points_value) DESC";

    mysqli_multi_query($link, $agentsquery) or die("MySQL Error: " . mysqli_error($link) . "<hr>\nQuery: $agentsquery");
    mysqli_next_result($link);
    mysqli_next_result($link);
    mysqli_next_result($link);

    if ($result = mysqli_store_result($link)) {
        $i = 0;
        while ($row = mysqli_fetch_array($result)){
            $number_of_apps = getAgentAppsWeek($row['agent_name'],$weeknum,$current_year);
            $i++;
?>

            <tr class="tr<?php echo ($i & 1) ?>">
                <td style="font-weight: bold;"><?php echo $row['agent_name'] ?></td>
                <td><?php echo $row['SUM(job_value)'] ?></td>
                <td><?php echo $row['SUM(points_value)'] ?></td>
                <td><?php echo $number_of_apps; ?></td>
            </tr>

<?php

        }
    }
?>

在为每个查询多次粘贴 mysqli_next_result 之后,它神奇地起作用了!耶!我理解它为什么起作用,因为我告诉它跳到下一个结果 3 次,所以它跳到查询 #4 的结果,这是我想要使用的查询。

不过对我来说似乎有点笨拙,如果你问我,应该只有一个类似 mysqli_last_result($link) 的命令......

感谢 rik 和 f00 的帮助,我最终到达了那里:)

于 2011-01-12T11:03:24.253 回答
1

我会通过创建一个存储过程来简化您尝试做的事情,该过程将产生领导者/代理统计信息,然后只需从您的 php(单次调用)中调用它,如下所示:

完整的脚本在这里: http: //pastie.org/1451802

或者,您可以将您的各个查询组合成一个 select/group by 语句。

见这里: http: //pastie.org/1451842

select
 leaders.agent_name, 
 sum(leaders.job_value) as sum_job_value, 
 sum(leaders.points_value) as sum_points_value 
from
(
select 
 agent_name, 
 job_number, 
 job_value, 
 points_value 
from 
 jobs 
where 
 year(booked_date) = 2011 and weekofyear(booked_date) = 2
union all
select distinct
 agent_name,
 0,0,0
from
 apps
where 
 year(booked_date) = 2011 and weekofyear(booked_date) = 2
) leaders
group by
 agent_name 
order by sum_points_value desc;

存储过程

drop procedure if exists list_leaders;

delimiter #
create procedure list_leaders
(
in p_year smallint unsigned,
in p_week tinyint unsigned
)
begin

  create temporary table tmp_leaders(
    agent_name varchar(20) not null,
    job_number int unsigned not null default 0, -- note the default values
    job_value decimal(3,1) not null default 0,
    points_value decimal(8,2) not null default 0
  )engine=memory;

  insert into tmp_leaders (agent_name, job_number, job_value, points_value) 
    select agent_name, job_number, job_value, points_value from jobs 
    where year(booked_date) = p_year and weekofyear(booked_date) = p_week;

  insert into tmp_leaders (agent_name) -- requires default values otherwise you will get nulls
    select distinct agent_name from apps
    where year(booked_date) = p_year and weekofyear(booked_date) = p_week;

  select 
    agent_name, 
    sum(job_value) as sum_job_value, 
    sum(points_value) as sum_points_value 
   from
    tmp_leaders
   group by
    agent_name order by sum_points_value desc;

  drop temporary table if exists tmp_leaders;

end#

delimiter ;

call list_leaders(year(curdate()), weekofyear(curdate()));

PHP 脚本

<?php

ob_start(); 

try
{
    $db = new mysqli("localhost", "foo_dbo", "pass", "foo_db", 3306);

    if ($db->connect_errno) 
        throw new exception(sprintf("Could not connect: %s", $db->connect_error));

    $sqlCmd = "call list_leaders(2011, 2)";
    $result = $db->query($sqlCmd);

    if(!$result) throw new exception(sprintf("Invalid query : %s", $sqlCmd));

    if($db->affected_rows <= 0){
        echo "no leaders found !";
    }
    else{
        $leaders = $result->fetch_all(MYSQLI_ASSOC);
        foreach($leaders as $ldr){
            // do stuff
            echo $ldr["agent_name"], "<br/>";
        }
    }
}
catch(exception $ex)
{
    ob_clean(); 
    echo sprintf("zomg borked - %s", $ex->getMessage());
}

if(!$db->connect_errno) $db->close();
ob_end_flush();
?>

现在有点简单-希望它有所帮助:)

于 2011-01-12T10:52:46.553 回答
1

将结果存储在变量中并最终使用该变量。

    do{
        if($result = $con->store_result()){
            $data=$result->fetch_all();
            $result->free();
        }
    } while($con->more_results()&&$con->next_result());
    echo(json_encode($data));
于 2017-07-28T13:32:42.310 回答
0

我想整理一下海报目前接受的解决方案,以使其更符合我认为的最佳实践。

  • 虽然多行 mysqli_next_result($link) 给出了预期的结果,但它看起来有点骇人听闻。因此,我将在他们的位置创建一个 DO-WHILE。
  • rik 涉及创建函数 mysqli_last_result($link) 的解决方案是多余的。我的 WHILE 条件将达到同样的效果。此外,rik 的代码混合了过程和面向对象的风格,应该避免这种情况。
  • 我不会在 php 和 html 之间跳来跳去。
  • 我将稍微调整一下类切换。
  • 我将 getAgentAppsWeek() 直接内联,因为我不喜欢创建只提到一次的变量;并且因为 Harry Weiner 在命名函数方面做得很好。
  • IMO 这更容易阅读。

    if(mysqli_multi_query($link,$agentsquery)){
        do{
            if($result=mysqli_store_result($link)){ // ignore if no record set
                while($row=mysqli_fetch_array($result)){
                    echo "<tr class=\"tr",(++$i & 1),"\">";
                        echo "<td style=\"font-weight:bold;\">",$row['agent_name'],"</td>";
                        echo "<td>",$row['SUM(job_value)'],"</td>";
                        echo "<td>",$row['SUM(points_value)'],"</td>";
                        echo "<td>",getAgentAppsWeek($row['agent_name'],$weeknum,$current_year),"</td>";
                    echo "</tr>";
                }
                mysqli_free_result($result);
            }
        } while(mysqli_more_results($link) && mysqli_next_result($link));
    }
    if($error_mess=mysqli_error($link)){
        echo "<tr class=\"error\"><td colspan=\"4\">Error: $error_mess</td></tr>";
    }
    //if any query returns false, mysqli_multi_query will stop
    // and the individual query error to blame will be provided.
    
于 2014-03-18T05:50:52.150 回答
0

我想我也会在这个问题上投入我的帽子(嘿,它仍然是程序性的和所有的爵士乐)。这不是万无一失的,但我一直在与 MySQLi 进行斗争,它是一群参与 multi_query 的快乐人,我无法让它以我想要的方式很好地发挥作用,或者具有我需要的灵活性。我看到了几个例子,其中一些程序员只是简单地运行explode(';', $sql_statements),这让我的眼睛流血了,这可能是多么可怕的错误。

我的解决方案可能对您不起作用,但这对我有用。(不,它也不是防弹的,但可以为我的特定应用程序工作)。

<?php
    $file = file_get_contents('test_multiple_queries.sql');
    $result = preg_split("/;(?=\s*(create|insert|update|alter|show|explain|truncate|drop|delete|replace|start|lock|commit|rollback|set|begin|declare|rename|load|begin|describe|help))/im", $file);
    $result = array_map('trim', $result);

    foreach($result as $sql_query) {

        // Procedural style
        $my_query = mysqli_query($link, $sql_query);

        // Now you can get errors easily, or affected_rows, or whatever
        //    using much simpler, readable code
        mysqli_error($link);
        mysqli_affected_rows($link);

        // or go crazy with some other stuff
        $words = preg_split("/\s+/", $sql_query);
        switch(strtolower($words[0])) {
            case 'insert':
                // do something nifty like...
                echo 'New ID: '.mysqli_insert_id($link)."\n";
                break;
            case 'drop':
                // obviously run this before the query, simply here for example
                echo 'Hey young (man|lady)! We don\'t drop anything!';
                break;
            case 'select':
                // hooray for selecting stuff
                while($rs = mysqli_fetch_assoc($my_query)) {
                    // have fun with data
                }
                break;
        }
    }
于 2015-10-06T20:46:40.350 回答