【问题标题】:MySQL to MySQLi Query issue when joining arrays加入数组时的 MySQL 到 MySQLi 查询问题
【发布时间】:2011-07-16 19:04:06
【问题描述】:

我正在尝试将一些 MYSQL 查询转换为 MYSQLI,但我遇到了问题,下面是我遇到问题的脚本的一部分,该脚本将查询转换为 csv:

$columns = (($___mysqli_tmp = mysqli_num_fields($result)) ? $___mysqli_tmp : false); 

// Build a header row using the mysql field names 

$rowe = mysqli_fetch_assoc($result);
$acolumns = array_keys($rowe);
$csvstring = '"=""' . implode('""","=""', $acolumns) . '"""';
$header_row = $csvstring; 

// Below was used for MySQL, Above was added for MySQLi
//$header_row = '';
//for ($i = 0; $i < $columns; $i++) {
//  $column_title = $file["csv_contain"] . stripslashes(mysql_field_name($result, $i)) . $file["csv_contain"];
//  $column_title .= ($i < $columns-1) ? $file["csv_separate"] : '';
//  $header_row .= $column_title;
//  } 
$csv_file .= $header_row . $file["csv_end_row"]; // add header row to CSV file 

// Build the data rows by walking through the results array one row at a time 
$data_rows = ''; 
while ($row = mysqli_fetch_array($result)) { 
  for ($i = 0; $i < $columns; $i++) { 
    // clean up the data; strip slashes; replace double quotes with two single quotes 
    $data_rows .= $file["csv_contain"] .$file["csv_equ"] .$file["csv_contain"] .$file["csv_contain"] . preg_replace('/'.$file["csv_contain"].'/', $file["csv_contain"].$file["csv_contain"], stripslashes($row[$i])) . $file["csv_contain"] .$file["csv_contain"] .$file["csv_contain"];
    $data_rows .= ($i < $columns-1) ? $file["csv_separate"] : ''; 
  } 
  $data_rows .= $this->csv_end_row; // add data row to CSV file 
} 
$csv_file .= $data_rows; // add the data rows to CSV file 

if ($this->debugFlag) { 
  echo "Step 4 (repeats for each attachment): CSV file built. \n\n"; 
} 

// Return the completed file 
return $csv_file; 

我遇到的问题是在为列标题构建标题行时 mysqli 不使用 field_names 所以我通过使用mysqli_fetch_assoc() 然后implode() 数组来获取列标题,添加,' s 等用于 csv。

这可行,但是当我生成 csv 时,我会在标题处于活动状态时删除第一个数据行,当我删除脚本的标题部分并将标题保留为空时,我会得到所有数据行和一个空白标题(如预期)。

所以在将我的标头加入数组到$csv_file 时,我一定遗漏了一些东西。

谁能指出我正确的方向?

非常感谢

【问题讨论】:

  • 有什么理由不能使用fputcsv
  • 只是因为我使用的代码自动通过电子邮件发送 csv 文件,我认为更改此代码比重新开始更容易
  • 编写自己的 CSV 格式化程序很容易出错,duplicates existing functionality。如果您需要字符串中的数据,您仍然可以通过写入php://temp 流(使用stream_get_contents 将结果保存到流中)或string stream 来使用fgetcsv

标签: php mysql arrays mysqli


【解决方案1】:

第三种选择是将循环体重构为一个函数,然后在进入循环之前在第一行调用这个函数。你可以使用fputcsv作为这个函数。

$csv_stream = fopen('php://temp', 'r+');

if ($row = $result->fetch_assoc()) {
    fputcsv($csv_stream, array_keys($row));

    fputcsv($csv_stream, $row);
    while ($row = $result->fetch_row()) {
        fputcsv($csv_stream, $row);
    }

    fseek($csv_stream, 0);
}
$csv_data = stream_get_contents($csv_stream);
if ($this->debugFlag) { 
  echo "Step 4 (repeats for each attachment): CSV file built. \n\n"; 
} 

// Return the completed file
return $csv_data;

因为这基本上与do ... while 循环做同样的事情,使用起来会更有意义。我提出了这个替代方案来展示循环体重构技术,当不同类型的循环没有意义时可以使用它。

最好同时使用mysqli_result::fetch_fieldsfputcsv

$csv_stream = fopen('php://temp', 'r+');

$fields = $result->fetch_fields();
foreach ($fields as &$field) {
    $field = $field->name;
}
fputcsv($csv_stream, $fields);

while ($row = $result->fetch_row()) {
    fputcsv($csv_stream, $row);
}

fseek($csv_stream, 0);
$csv_data = stream_get_contents($csv_stream);
if ($this->debugFlag) { 
  echo "Step 4 (repeats for each attachment): CSV file built. \n\n"; 
} 

// Return the completed file
return $csv_data;

如果您可以要求 PHP 至少为 5.3 版,您可以将生成标题行的 foreach 替换为对 array_map 的调用。诚然,这并没有太大的优势,我只是觉得函数式方法更有趣。

fputcsv($csv_stream, 
        array_map(function($field) {return $field->name}, 
                  $result->fetch_fields()));

【讨论】:

  • 嗨,您的第二个选项给了我错误:致命错误:无法在第 277 行的 class.email-query-csv.php 中使用 stdClass 类型的对象作为数组(第 277 行:foreach ($fields as &$field) {) 你的第一个选项很有效,给了我字段名称和数据行,但是数据行到处都是,第一个数据行是完美的,但是之后的那些重复了每个字段数据两次(复制它们)所以不确定那里发生了什么?
  • 抱歉第 277 行是:$field = $field['name'];
  • mysqli_result::fetch_fields 返回一个对象数组,而不是我最初想到的数组数组,所以你必须使用属性访问运算符(-&gt;)而不是数组索引运算符(@987654334 @)。重复字段是由于mysqli_result::fetch_array 的默认模式MYSQLI_BOTH。我通常是 PDO 人。查看更新(将第 277 行更改为 $field = $field-&gt;name;fetch_array 更改为 fetch_row)。
【解决方案2】:

正如您所观察到的,您使用第一行来获取字段名称,但没有使用该行中的数据。显然,您需要更改代码才能同时获得这两样东西。

您可以通过多种方式执行此操作。最合适的一种是使用mysqli_fetch_fields(),而不是从结果对象中获取字段元数据。

http://www.php.net/manual/en/mysqli-result.fetch-fields.php

或者,您可以在代码中将循环设置为do... while 而不是while

【讨论】:

  • 正在使用的字段名称 $header_row = $csvstring;并确实出现在 csv 中,但问题似乎是标题覆盖了 $data_rows 中的第一行数据,所以在 csv 中我得到了我的标题(字段名称)但丢失了第一行数据。
  • @Ben:Hammerite 说得对。您没有使用来自$rowe 的值;您永远不会将第一行中的值写入 $csv_file。
  • 如果我不使用来自 $rowe 的值,来自 $rowe 的值会显示在我输出的 csv 文件中吗?我很困惑!
  • 您正在使用$rowe 来查找字段的名称。但是,$rowe 是结果集中的一行(第一行,即您第一次调用 mysqli_fetch_assoc 检索到的行)并且您没有使用该数据。结果集中的任何行都可用于查找字段的名称;第一行没有什么特别的。碰巧您正在使用第一行来获取列元数据,但您没有使用该行中的实际数据。
  • @Hammerite 啊啊啊好吧我明白你在说什么,抱歉我不太擅长这些东西。我已经对其进行了排序,但我会认为这是一种混乱的方式。我已经将 $rowe 部分移到了代码中,并为该部分调用了一个新查询,然后加入了它。这似乎奏效了。
猜你喜欢
  • 1970-01-01
  • 2012-07-19
  • 2019-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-10
相关资源
最近更新 更多