查询已停止运行,而不是插入零值

时间:2016-07-21 11:25:02

标签: php mysql

我们有这个MySQL查询,我们希望从date_time表中找到price_openprice,并将这两个值更新为price_datetimeprice_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_iddate_time都不匹配,fc.price_datetimefc.price_open列将显示{{1 }和0000-00-00 00:00:00值。但是,在执行PHP代码时,它不会插入零值,而是在遇到第一个&#34; no matching&#34; 0.00ticker_id并且无法继续。我们花了很长时间搞清楚如何修复它,遗憾的是,我们使用的方法都无法解决这个问题。

社区的任何帮助都非常感谢。

谢谢。 :)

1 个答案:

答案 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限制。