如何确定导致使用mysqli_multi_query错误的查询?(How to identify t

2019-06-27 16:55发布

使用例如从其他地方SO,以更好地捕捉“隐藏”的错误。 而下面的代码将捕获并返回一个错误,是可以改善这个报告查询时其错误?

用下面的代码,输出为:

Columns: 18
Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FRO inventory' at line 1

代码进行测试:

$query = "SELECT * FROM orders WHERE location = 'IN' ORDER BY orderNum DESC LIMIT 20;";
$query .= "SELECT * FRO inventory";             //  With error
$ord = array();
$invent = array();

if(mysqli_multi_query($link, $query)) {
    do {
        // fetch results
        if($result = mysqli_store_result($link)) {
           echo 'Columns: ' . mysqli_field_count($link) . "<br>"; 
           while($row = mysqli_fetch_assoc($result)) {
                if(count($row) > 17)
                    $orders[] = $row;
                elseif(count($row) == 6)
                    $inv[] = $row;
            }
        }
        if(!mysqli_more_results($link))
            break;
        if(!mysqli_next_result($link)) {
            // report error
            echo 'Error: ' . mysqli_error($link);
            break;
        }
    } while(true);
    mysqli_free_result($result);
}

Answer 1:

这里不仅会提高你的错误信息质量的方法,它会提高你处理你的结果集的方式。

$q["Orders"]="SELECT * FROM orders WHERE location = 'IN' ORDER BY orderNum DESC LIMIT 20";
$q["Inventory"]="SELECT * FRO inventory";

if(!$link=mysqli_connect("host","user","pass","db")){
    echo "Failed to connect to MySQL: ",mysqli_connect_error();
}elseif(mysqli_multi_query($link,implode(';',$q))){
    do{
        $q_key=key($q);  // current query's key name (Orders or Inventory)
        if($result=mysqli_store_result($link)){   // if a result set... SELECTs do
            while($row=mysqli_fetch_assoc($result)){  // if one or more rows, iterate all
                $rows[$q_key][]=$row;
            }
            mysqli_free_result($result);
            echo "<div><pre>";  // <pre> is for easier array reading
                var_export($rows[$q_key]);
            echo "</pre></div>";
        }
    } while(next($q) && mysqli_more_results($link) && mysqli_next_result($link));
}
if($mysqli_error=mysqli_error($link)){  // check & declare variable in same step to avoid duplicate func call
    echo "<div style=\"color:red;\">Query Key = ",key($q),", Query = ",current($q),", Syntax Error = $mysqli_error</div>";
}

在第一个查询错误 :如果你的第一个查询试图访问不被提名的数据库中存在的表像: ordersXYZ数组$rows不会存在,没有var_export()会发生,你会看到这样的响应:

查询键=订单,查询= SELECT * FROM ordersXYZ WHERE位置= 'IN' ORDER BY ORDERNUM DESC LIMIT 20,语法错误=表 '[someDB] .ordersXYZ' 不存在

关于第二个查询错误 :如果你的第一个查询是成功的,但你的第二个查询试图访问像一个不存在的表: inventory2
$rows["Orders"]将持有该行的数据,将var_export() “版, $row["Inventory"]将不存在,你会看到这样的回应:

查询键=清单,查询= SELECT * FROM inventory2,语法错误=表 '[someDB] .inventory2' 不存在

没有错误 :如果两个查询是免费的错误,你的$rows阵列将充满期望的数据和var_export() “版,并不会有错误响应。 随着保存在查询的数据$rows ,你可以访问你想要什么$rows["Orders"]$rows["Inventory"]


需要注意的事项:

  1. 您可能注意到,我在同一时间,使变量声明和有条件的检查,这使得代码更干。

  2. 正如我的方法是使用implode()与上一个分号elseif线,可千万不要尾随分号添加到您的查询。

  3. 这组查询总是返回的结果集,因为都是SELECT查询,如果您有疑问的混合收集affect_rows ,你会发现这个链接一些有用的信息( https://stackoverflow.com/a/22469722/2943403 ) 。

  4. mysqli_multi_query()会尽快有一个错误停止运行的查询。 如果你期望赶上“所有”的错误,你会发现,有永远不能超过一个。

  5. 在OP的问题和解决方案的编写条件断点就像是不可取的。 虽然自破发点,可在其他情况下被正确地使用,这种情况下,破发点应位于内侧while()的声明do()块。

  6. 返回零行的查询将不会导致错误信息-它只是不会产生任何的子阵列$rows ,因为while()循环将不进入。

  7. 通过使用key()函数时,OP的if/elseif计数每个结果集行中的列可避免条件。 这是更好的做法,因为在每个迭代上运行的条件可以在某些情况下变得昂贵。 请注意,该阵列指针的内部前进$q在每个端do()迭代。 这是你不会PHP手册页面上找到一个附加的技术; 它允许key()按预期工作。

  8. 而且,当然,在<div><pre>var_export()...</pre></div>行可以从工作代码中删除-这纯粹是为了演示。

  9. 如果你要运行这个代码块重复使用变量之后的任何更多的查询,一定要清除所有的变量,使残留数据不干预。 例如$mysqli_error=null; // clear errors $mysqli_error=null; // clear errorsreset($q); // reset array pointer reset($q); // reset array pointer

  10. 你要小心,你自己的判断这有些含糊的警告: http://php.net/manual/en/mysqli.use-result.php :

    一个不应该使用mysqli_use_result()如果执行在客户端上进行大量的处理,因为这会占用服务器和防止其他线程更新从其中数据被取出的任何表。

  11. 最后也是最重要的出于安全考虑,不要公开展示查询或查询错误的信息-你不想险恶看到这样的反馈。 同样重要的是,时刻保护您的查询从注射黑客。 如果查询包括用户提供的数据,您需要过滤/在使用它之前的数据消毒死亡mysqli_multi_query() 在用户输入问题时其实我很强烈的建议是将远离mysqli_multi_query()并使用或者准备好的语句或PDO为你的数据库交互的安全性更高的水平。



Answer 2:

在你做循环,添加一个计数器,每一个成功的mysqli_next_result增加计数器。 一旦mysqli_next_result返回false,输出计数器为好。



Answer 3:

这适用于两个查询。

如果错误是在第一个,对第一查询,以PHP的响应是错误消息,和用于第二(这将不会触发),消息在第一闲聊。

如果错误是在第二,第一的响应返回和第二得到错误信息。

我使用关联数组和坭兴数组元素[0]。 这增加了[“错误”]键只有在有相关的错误。

最后,我不是最好的PHPer,所以它是由你来解决什么是丑陋的。

$query_nbr=0;

if (mysqli_multi_query($link,$query ))
{ 
  do
  { 
    unset($field_info) ;            $field_info = array() ;
    unset($field_names) ;           $field_names = array() ;
    unset($values) ;                $values = array(array()) ;

    if ($result = mysqli_store_result($link))
    { 
      $query_nbr += 1 ; 
      $rows_found = mysqli_num_rows($result);
      $fields_returned = mysqli_num_fields($result);
      $field_info = mysqli_fetch_fields($result);

      $field_nbr=0;
      foreach ($field_info as $fieldstuff)
      { $field_nbr +=1 ;
        $field_names[$field_nbr] = $fieldstuff->name ;
      }

      $now = date("D M j G:i:s T Y") ;

      if ($query_nbr == 1)
      { 
        $result_vector1 = array('when'=>$now) ;
        $result_vector1['nrows']=0;
        $result_vector1['nrows']=$rows_found ;
        $result_vector1['nfields']=$fields_returned ;
        $result_vector1['field_names']=$field_names ;
      }
      else 
      { 
        $result_vector2 = array('when2'=>$now) ;
        $result_vector2['nrows2']=0;
        $result_vector2['nrows2']=$rows_found ;
        $result_vector2['nfields2']=$fields_returned ;
        $result_vector2['field_names2']=$field_names ;
      }

      $row_nbr=0 ;
      while ($row = mysqli_fetch_array($result, MYSQLI_BOTH))
      { 
        $row_nbr++ ;
        for ($field_nbr=1;$field_nbr<=$fields_returned;$field_nbr++)
        {
          $values[$row_nbr][$field_names[$field_nbr]]    =$row[$field_nbr-1] ;
        }
      }
      mysqli_free_result($result) ;

      unset($values[0]) ;
      if ($query_nbr == 1)
      {$result_vector1['values']=$values ;}
      else
      {$result_vector2['values2']=$values ;}

    }  // EO if ($result = mysqli_store_result($link))

  } while (mysqli_more_results($link) && mysqli_next_result($link)) ;

}  // EO  if (mysqli_multi_query($link,$query ))
else 
{
  // This will be true if the 1st query failed
  if ($query_nbr == 0)
  { 
    $result_vector1['Error'] = "MySQL Error #:  ".mysqli_errno($link).":  ".mysqli_error($link) ;
    $result_vector2['Error'] = "MySQL Error in first query." ;
  }

}  // EO MySQL

//  Here we only made it through once, on the 2nd query
if ( $query_nbr == 1 && $nqueries == 2  && empty( $result_vector2 ) )
{
  $result_vector2['Error'] = "MySQL Error #:  ".mysqli_errno($link).":  ".mysqli_error($link) ;
}


Answer 4:

要回答我的问题,并且由于文件很糟糕,这里有一个解决方案,希望能帮助别人。 少了什么是捕捉一号查询错误的方式。 (myqsqli_multi_query的隐蔽行动是很难理解的。)

现在,您在$犯错数组项。

$q[1] = "SELECT * FROM orders WHERE location = 'IN' ORDER BY orderNum DESC LIMIT 20";
$q[2] = "SELECT * FROM inventory";
$ord = array();
$invent = array();
$err = array();
$c = 1;

if(mysqli_multi_query($link, implode(';', $q))) {
    do {
        // fetch results
        if($result = mysqli_use_result($link))
            while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
                if(count($row) > 17)
                    $orders[] = $row;
                elseif(count($row) == 6)
                    $inv[] = $row;
            }
        }
        $c++;
        if(!mysqli_more_results($link))
            break;
        if(!mysqli_next_result($link) || mysqli_errno($link)) {
            // report error
            $err[$c] = mysqli_error($link);
            break;
        }
    } while(true);
    mysqli_free_result($result);
}
else
    $err[$c] = mysqli_error($link);

mysqli_close($link);


文章来源: How to identify the query that caused the error using mysqli_multi_query?