这是常见问题,但我没有选择这样编码只是为了在Excel文件中获取适当的标题和正文
这里是如何开始的
当请求打印时,我首先开始查询以获取数据库中的标题
SELECT instruments.in_id, instrument_parameters.ip_id,
CASE WHEN gv_x_ipid = -1 THEN 'datetime' ELSE '' END xlabel,
CASE WHEN ip_label LIKE '%Reservoir%' THEN 0 ELSE in_order END legendIndex,
CASE WHEN in_name = 'General' THEN ip_label ELSE in_name END ylabel
FROM graph_plot
LEFT JOIN attributes gptype ON gp_type = gptype.at_id
LEFT JOIN graph_value ON gp_id = gv_gpid
LEFT JOIN instrument_parameters ON gv_y_ipid = ip_id
LEFT JOIN attributes pmunit ON ip_unit = pmunit.at_id
LEFT JOIN instrument_reading yvalue ON gv_y_ipid = iv_ipid
LEFT JOIN instruments ON iv_inid = in_id
WHERE gp_diid = :di_id AND
gp_type = :rpt_type AND
iv_status = 'Y' AND
iv_inid in (".implode(",", $coll->inid).") AND
gv_y_ipid in (".implode(",", $coll->ipid).")
GROUP BY ylabel
ORDER BY legendIndex
这将产生一些标题,我将使它像这样
DATE | Instrument1 | Instrument2 | Instrument3
基于上面的查询,Instrument?
将是动态的。我将它存储在新变量中。但保存数据库结果的原始变量保持不变。
稍后,使用相同的参数:di_id
和:rpt_type
,还有另外一个参数,startDt
和endDt
来进行另一个查询,只是为了返回一个可用的长列表数据库中的日期。这基于startDt
和endDt
。
$sql2 = "SELECT iv_reading FROM instrument_reading WHERE iv_inid = :inid AND iv_ipid = :ipid AND iv_date = :dt AND iv_status = 'Y'";
完成日期后,我会像这样做两个循环
foreach ($dates as $key => $dt) {
foreach ($resp as $InstNo => $InstRow) {
try {
$stmt2->execute(array(':dt' => $dt, ':inid' => $InstRow->in_id, ':ipid' => $InstRow->ip_id));
$rowDb = $stmt2->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT);
} catch(PDOException $e) {
echo '{"error":{"text":"'. $e->getMessage() .'"}}';
}
}
}
首先,它开始循环日期,然后开始循环标题(基于在获取日期之前进行的查询)。我的问题一直困在这里
$stmt2->execute(array(':dt' => $dt, ':inid' => $InstRow->in_id, ':ipid' => $InstRow->ip_id));
你怎么看?有没有更好的方法来解决这个问题?
有关您的信息,我使用Slim和PHPExcel。 PHPExcel可能存在内存问题,我想切换到Spout,但文档仍然是关于基本内容的。
答案 0 :(得分:6)
在SQL中,您可以考虑使用limit clause来减轻内存负载,如下所示:
$handle = fopen("file.csv", "wb");
$statement = "
SELECT instruments.in_id, instrument_parameters.ip_id,
CASE WHEN gv_x_ipid = -1 THEN 'datetime' ELSE '' END xlabel,
CASE WHEN ip_label LIKE '%Reservoir%' THEN 0 ELSE in_order END legendIndex,
CASE WHEN in_name = 'General' THEN ip_label ELSE in_name END ylabel
FROM graph_plot
LEFT JOIN attributes gptype ON gp_type = gptype.at_id
LEFT JOIN graph_value ON gp_id = gv_gpid
LEFT JOIN instrument_parameters ON gv_y_ipid = ip_id
LEFT JOIN attributes pmunit ON ip_unit = pmunit.at_id
LEFT JOIN instrument_reading yvalue ON gv_y_ipid = iv_ipid
LEFT JOIN instruments ON iv_inid = in_id
WHERE gp_diid = :di_id
AND gp_type = :rpt_type
AND iv_status = 'Y'
AND iv_inid in (".implode(",", $coll->inid).")
AND gv_y_ipid in (".implode(",", $coll->ipid).")
GROUP BY ylabel
ORDER BY legendIndex
LIMIT 250
";
$prep = $dbh->prepare($statement);
for ($i = 0; $prep -> rowCount < 250; $i+= 250) {
fputcsv(prep->fetchAll());
$prep = $dbh->prepare($statement.' OFFSET'.$i);
}
fclose($handle);
或者,您可以使用system并致电SELECT INTO,设置权限(如有必要),鲍勃是您的叔叔。
答案 1 :(得分:5)
您尚未终止filter
循环。
fetch
得到&#34; next&#34;排列或关闭游标&#39;并终止。
您是否希望获得一排?如果是这样,请考虑进行fetchAll。 (注意:结果集在数组中可能是一个额外的级别。)
答案 2 :(得分:0)
PDO MySQL 驱动程序会做一些缓冲,这会在循环大型数据集时导致内存耗尽。您可以使用 $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
关闭此功能,这应该可以解决问题。
$pdo = new PDO('mysql:localhost', $username, $password);
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt = $pdo->prepare('SELECT * FROM instrument...');
$stmt->execute($parameters);
while($row = $stmt->fetch()) {
// Insert logic to write the row to the destination
}
如果您只想为该查询设置属性,您也可以这样做:
$stmt = $pdo->prepare('SELECT * FROM instrument...', [
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY
]);
请记住,在完成未缓冲的查询之前,您将无法运行其他查询。如果不需要剩余的结果,可以使用 $stmt->closeCursor()
提前关闭旧游标。我也无法谈论它的性能,但它在编写一次性脚本时解决了我的问题。
MySQL 的文档中简要提到了该设置: https://dev.mysql.com/doc/connectors/en/apis-php-pdo-mysql.html