2016-07-21 6 views
0

Wir haben diese MySQL-Abfrage, wo wir die date_time und price_open aus price Tabelle und aktualisieren diese beiden Werte in die price_datetime und price_open Spalten in comment Tabelle finden wollen:Abfrage gestoppt laufen statt Einfügen Nullwerte

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; 

was wir zu PHP + MySQL konvertiert der Hoffnung auf eine höhere Effizienz und viel schneller Prozess:

<?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; 

?> 

Verwendung des MySQL-Abfrage, wenn es keine Übereinstimmung von 012.318.036 istund date_time aus beiden Tabellen, die fc.price_datetime und fc.price_open Spalten zeigen 0000-00-00 00:00:00 und 0.00 Werte. Wenn Sie den PHP-Code ausführen, wird er jedoch nicht die Nullwerte einfügen, sondern erst dann, wenn sein allererstes "no matching" von ticker_id und date_time auftritt und er nicht fortgesetzt werden kann. Wir haben lange darüber nachgedacht, wie wir es beheben können, leider kann keine der Möglichkeiten, die wir verwenden, dies beheben.

Jede Hilfe von der Gemeinschaft wird definitiv sehr geschätzt.

Vielen Dank. :)

+0

Wenn Sie "in die Kommentartabelle einfügen" möchten, warum verwenden Sie 'update'? –

+0

@GordonLinoff Entschuldigung, falscher Begriff wird verwendet, ich möchte "updaten", weil es bereits vorhandene Spalten mit Informationen gefüllt gibt. Ich werde bearbeiten. – Shyuan

Antwort

1

Sie überprüfen nicht, ob ein Datensatz von Preis zurückgegeben wird. Daher versucht Ihr Code nur das erste und das zweite Element des Ergebnisarrays auszuwählen, wenn dieses Array null ist. Sie landen dann wahrscheinlich mit einer Anweisung, die versucht, jedem der Felder price_datetime und price_open Leerzeichen zuzuweisen. Mit dem Preisdatum haben Sie Anführungszeichen um den leeren Wert und mysql wird wahrscheinlich damit umgehen, aber für price_open haben Sie keine Anführungszeichen um den erwarteten numerischen Wert. Daher landen Sie mit einer ungültigen Update-Anweisung (etwas wie die folgenden) nach oben: -

UPDATE flaggedcomment price_datetime='', price_open= WHERE ticker_id=123 AND date_time='2016-01-01 00:00:00'; 

Wie Sie mehr SQL-Anweisungen ausführen, das Updates zu tun, ich erwarte, dass es nicht nach dem ausgeführt wird ungültige Aussage

Ein schnelles Spiel mit Ihrem Code und das folgende sollte funktionieren. Dies überprüft die zurückgegebene Zeile und wenn eine nicht gefunden wird, verwendet sie nur die Standardwerte (null wie) für die 2 Felder, die Sie aktualisieren möchten.

<?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; 

?> 

Allerdings vermute ich, dass um das Ergebnis einer Abfrage Looping und eine weitere Abfrage für jede Zeile in PHP tun wird als eine gut ausgebaute einzelne Update-Abfrage langsamer.

Wenn Sie die Ergebnisse, wie Sie es jetzt tun, umschlingen möchten, kann es schneller sein, eine tmp-Tabelle zu erstellen und die Zeilen einzufügen (da Sie Hunderte von Zeilen mit einer einzigen Anweisung einfügen können) und dann aktualisieren flaggedcomment Tabelle mit einer einzigen update-Anweisung, die es mit der tmp-Tabelle verbindet

EDIT - Wenn Sie die Tabelle deklariert und ein wenig Beispieldaten kann ich versuchen, es in einer einzigen SQL-Anweisung zu tun.

Ein erster Versuch (ungetesteter) wäre: -

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; 

Dies wird die zusätzliche scheinbar redundante Unter Abfrage, um hoffentlich eine MySQL Beschränkung umgehen, eine Tabelle auf der Aktualisierung, die auch in einer Unterabfrage verwendet wird.

+1

Hallo Kickstart, Entschuldigung für die späte Antwort, als ich beide Ihre Lösungen getestet habe. Ihre MySQL-Abfrage ist effizienter (fast um die Hälfte) als meine ursprüngliche MySQL-Abfrage. Ich habe auch getestet mit Ihrem PHP + MySQL-Code auf meinem Datensatz, das funktioniert auch gut! PHP + MySQL dauert nur ein paar Stunden, was viel effizienter ist als die MySQL-only-Abfrage. Vielen Dank für Ihre Hilfe und ausführliche Erklärung! Wir können sehen, wo unsere Fehler sind. :))) – Shyuan