我们有这个MySQL查询,我们希望从date_time
表中找到price_open
和price
,并将这两个值更新为price_datetime
和price_open
comment
表中的列:
UPDATE comment AS fc
INNER JOIN price AS p
ON p.ticker_id = fc.ticker_id
AND p.date_time =
( SELECT pi.date_time
FROM price AS pi
WHERE pi.ticker_id = fc.ticker_id
AND pi.date_time >= fc.date_time
ORDER BY pi.date_time ASC
LIMIT 1
) SET
fc.price_datetime = p.date_time,
fc.price_open = p.price_open;
我们转换为PHP + MySQL希望提高效率和更快的过程:
<?php
ob_flush();
flush();
usleep(160);
$tickers = array();
$stmt = $mysqli->prepare("SELECT ticker_id, date_time FROM flaggedcomment order by ticker_id, date_time");
$stmt->execute(); //Execute prepared Query
$stmt->bind_result($tid, $dt);
$arr_index = 0;
while ($stmt->fetch() ) {
$tickers[$arr_index] = array();
$tickers[$arr_index]["id"] = $tid;
$tickers[$arr_index]["dt"] = $dt;
$arr_index++;
}
/* free result set */
$stmt->free_result();
$record_index = 0;
$flaggedcomment_index = 0;
$sql = "";
// get total tickers
$total_tickers = count($tickers);
echo "Total records: " . $total_tickers . "<br />";
foreach ($tickers as $ticker) { //fetch values
$stmt = $mysqli->prepare("SELECT price_open, date_time FROM price WHERE ticker_id =? AND date_time >=? ORDER BY date_time ASC LIMIT 1;");
$stmt->bind_param("is",$ticker["id"], $ticker["dt"]); // two params: one is integer, and other one is string
$stmt->execute(); //Execute prepared Query
$results = $stmt->get_result();
$myrow = $results->fetch_row();
$set_string = "SET";
// bind values
$price_open = $myrow[0];
$date_time = $myrow[1];
// set initial insert query value
$set_string .= " price_datetime='". $date_time ."'";
$set_string .= ", price_open=". $price_open;
$set_string .= " WHERE ticker_id=". $ticker["id"] ." AND date_time='" . $ticker["dt"] ."'";
if($set_string != ""){
$sql .= "UPDATE flaggedcomment ". $set_string . ";";
}
$idx = $record_index + 1;
if(($record_index + 1) % 100 == 0){
?>
<script>
$('#page-wrap > h1').html("Processing Ticker id #" + <?= $ticker["id"]; ?> + " - Record #" + <?= $idx; ?>);
</script>
<?php
ob_flush();
flush();
usleep(160);
}
$record_index++;
/* free result set */
$stmt->free_result();
} // end while fetch ticker id
$update_flaggedcomment_qry = "LOCK TABLES flaggedcomment WRITE; ". $sql . "UNLOCK TABLES; ";
echo $update_flaggedcomment_qry;
//echo "<br />";
if ($mysqli->multi_query($update_flaggedcomment_qry)) {
// nothing
} else {
echo "Error updating record: " . $mysqli->error . "<br />";
$mysqli->close();
exit;
}
echo "<span style='color:blue;'> <b> Done. </b> </span>";
ob_end_flush();
exit;
?>
使用MySQL查询,如果两个表中的ticker_id
和date_time
都不匹配,fc.price_datetime
和fc.price_open
列将显示{{1 }和0000-00-00 00:00:00
值。但是,在执行PHP代码时,它不会插入零值,而是在遇到第一个&#34; no matching&#34; 0.00
和ticker_id
并且无法继续。我们花了很长时间搞清楚如何修复它,遗憾的是,我们使用的方法都无法解决这个问题。
社区的任何帮助都非常感谢。
谢谢。 :)
答案 0 :(得分:1)
您不会检查是否有从价格返回的记录。因此,当该数组为null时,您的代码只会尝试选择结果数组的第一个和第二个元素。然后,您可能会尝试为每个 price_datetime 和 price_open 字段分配空白。使用 price_datetime ,您在空值周围有引号,而mysql可能会处理此问题,但对于 price_open ,您没有围绕预期数值的引号。因此,您将使用无效的更新语句(如下所示): -
UPDATE flaggedcomment price_datetime='', price_open= WHERE ticker_id=123 AND date_time='2016-01-01 00:00:00';
当您一次执行多个SQL语句来执行更新时,我希望它在无效语句之后不会执行任何操作。
使用您的代码快速播放以下内容应该可行。这将检查返回的行,如果找不到,则只使用您要更新的2个字段的默认值(零样)。
<?php
ob_flush();
flush();
usleep(160);
$tickers = array();
$stmt = $mysqli->prepare("SELECT ticker_id, date_time FROM flaggedcomment order by ticker_id, date_time");
$stmt->execute(); //Execute prepared Query
$stmt->bind_result($tid, $dt);
$arr_index = 0;
while ($stmt->fetch() )
{
$tickers[$arr_index] = array();
$tickers[$arr_index]["id"] = $tid;
$tickers[$arr_index]["dt"] = $dt;
$arr_index++;
}
/* free result set */
$stmt->free_result();
$record_index = 0;
$flaggedcomment_index = 0;
$sql = "";
// get total tickers
$total_tickers = count($tickers);
echo "Total records: " . $total_tickers . "<br />";
foreach ($tickers as $ticker)
{ //fetch values
$stmt = $mysqli->prepare("SELECT price_open, date_time FROM price WHERE ticker_id =? AND date_time >=? ORDER BY date_time ASC LIMIT 1;");
$stmt->bind_param("is",$ticker["id"], $ticker["dt"]); // two params: one is integer, and other one is string
$stmt->execute(); //Execute prepared Query
$results = $stmt->get_result();
if ($myrow = $results->fetch_assoc())
{
$price_open = $myrow['price_open'];
$date_time = $myrow['date_time'];
}
else
{
$price_open = 0.00;
$date_time = "0000-00-00 00:00:00";
}
$sql .= "UPDATE flaggedcomment SET";
$sql .= " price_datetime='". $date_time ."'";
$sql .= ", price_open=".$price_open;
$sql .= " WHERE ticker_id=". $ticker["id"] ." AND date_time='" . $ticker["dt"] ."';";
$idx = $record_index++;
if(($record_index + 1) % 100 == 0)
{
?>
<script>
$('#page-wrap > h1').html("Processing Ticker id #" + <?= $ticker["id"]; ?> + " - Record #" + <?= $idx; ?>);
</script>
<?php
ob_flush();
flush();
usleep(160);
}
$record_index++;
/* free result set */
$stmt->free_result();
} // end while fetch ticker id
$update_flaggedcomment_qry = "LOCK TABLES flaggedcomment WRITE; ". $sql . "UNLOCK TABLES; ";
echo $update_flaggedcomment_qry;
//echo "<br />";
if ($mysqli->multi_query($update_flaggedcomment_qry)) {
// nothing
}
else
{
echo "Error updating record: " . $mysqli->error . "<br />";
$mysqli->close();
exit;
}
echo "<span style='color:blue;'> <b> Done. </b> </span>";
ob_end_flush();
exit;
?>
但是我怀疑循环一个查询的结果并为php中的每一行做另一个查询将比构造良好的单个更新查询慢。
如果你想像现在这样循环结果,可能会更快创建一个tmp表并将行插入(因为你可以用一个语句插入数百行),然后更新你的< em> flaggedcomment 表,其中包含一个将其连接到tmp表的更新语句
编辑 - 如果您可以发布表声明和一些示例数据,我将尝试在单个SQL语句中执行此操作。
首次尝试(未经测试)将是: -
UPDATE comment AS fc
INNER JOIN price AS p
ON p.ticker_id = fc.ticker_id
INNER JOIN
(
SELECT *
FROM
(
SELECT fc.ticker_id,
MIN(pi.date_time) AS date_time
FROM comment AS fc
INNER JOIN price AS pi
ON pi.ticker_id = fc.ticker_id
AND pi.date_time >= fc.date_time
GROUP BY fc.ticker_id
) sub1
) sub0
ON p.ticker_id = sub0.ticker_id
AND p.date_time = sub0.date_time
SET fc.price_datetime = p.date_time,
fc.price_open = p.price_open;
这是使用额外的看似冗余的子查询,希望在更新同样用于子查询的表时绕过MySQL限制。