We have this MySQL query where we want to find the date_time and price_open from price table and update these two values into the price_datetime and price_open columns in comment table:
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;
Which we converted to PHP+MySQL hoping for a more efficiency and much faster process:
<?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;
?>
Using the MySQL query, if there's no match of ticker_id and date_time from both tables, the fc.price_datetime and fc.price_open columns will show 0000-00-00 00:00:00 and 0.00 values. However, when executing the PHP code, instead of inserting the zero values, it will stop when it encounters its very first "no matching" of ticker_id and date_time and cannot continue. We've spent a long time figuring out on how to fix it, unfortunately, none of the ways we use can fix this.
Any help from the community is definitely much appreciated.
Thank you. :)
You do not check if there is a record returned from price . Hence your code just tries picking the first and second elements of the result array when that array is null. You then likely land up with a statement trying to assign blank to each of the price_datetime and price_open fields. With the price_datetime you have quotes around the empty value and mysql will probably cope with this, but for price_open you do not have quotes around the expected numeric value. Hence you will land up with an invalid update statement (some like the following):-
UPDATE flaggedcomment price_datetime='', price_open= WHERE ticker_id=123 AND date_time='2016-01-01 00:00:00';
As you are executing multiple SQL statements at once to do the updates, I expect that it won't execute any after the invalid statement.
A quick play with your code and the following should work. This checks the returned row and if one isn't found it just uses the default (zero like) values for the 2 fields you want to update.
<?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;
?>
However I suspect that looping around the result of one query and doing another query for each row in php will be slower than a well constructed single update query.
If you do want to loop around the results like you are doing now it may be quicker to create a tmp table and insert the rows to that (as you can insert hundreds of rows with a single statement) and then update your flaggedcomment table with a single update statement that joins it to the tmp table
EDIT - If you can post the table declares and a bit of sample data I will have an attempt at doing it in a single SQL statement.
A first attempt (untested) would be:-
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;
This is using the extra seemingly redundant sub query to hopefully bypass a MySQL restriction on updating a table that is also used in a subquery.
Related
This question already has answers here:
Using result of query to another query with IN()
(2 answers)
Closed 1 year ago.
I'm currently using PDO to do a select on a MySQL table and I have it printing the results, which are correct in terminal.
I'm trying to apply a 'while' loop to it that selects records from an odbc database where the order_id from the first query is equal to the invnoc in the 2nd query. I think my issue is how I call the order_id and execute the statement in the DB2 portion.
If i run this:
$ordStatSql = 'SELECT order_id, order_status, is_placement, date_updated
FROM order_status';
try{
$ordStat = $MysqlConn->prepare($ordStatSql);
$result = $ordStat->execute();
}
catch(PDOException $ex)
{
echo "QUERY FAILED!: " .$ex->getMessage();
}
while($row = $ordStat->fetch(PDO::FETCH_ASSOC))
{
echo $row['order_id'] . $row['order_status'] . $row['is_placement'] . $row['date_updated'] . "\n";
}
It runs fine, no errors, and prints every row that I anticipate.
But the full script:
$ordStatSql = 'SELECT order_id, order_status, is_placement, date_updated
FROM order_status';
try{
$ordStat = $MysqlConn->prepare($ordStatSql);
$result = $ordStat->execute();
}
catch(PDOException $ex)
{
echo "QUERY FAILED!: " .$ex->getMessage();
}
while($row = $ordStat->fetch(PDO::FETCH_ASSOC))
{
echo $row['order_id'] . $row['order_status'] . $row['is_placement'] . $row['date_updated'] . "\n";
$detailStatCheck = '
SELECT
invnoc as INVOICE,
fstatc as STATUS,
cstnoc AS DEALER,
framec AS FRAME,
covr1c AS COVER,
colr1c AS COLOR ,
extd2d AS SHIPDATE,
orqtyc AS QUANTITY
FROM GPORPCFL
WHERE invnoc IN ?
ORDER BY invnoc asc
';
try{
$detailCheck = $DB2conn->prepare($detailStatCheck);
$detailRslt = $detailCheck->execute(['order_id']);
$count2 = $detailCheck->rowcount();
}
catch(PDOException $ex)
{
echo "QUERY FAILED!: " .$ex->getMessage();
}
}
echo "Matches:" . $count2
It prints the same order_id numbers and obviously takes longer but matches shows -1. I know it's pulling matches because I run it manually and it matches every record. I'm wondering if I'm looping incorrectly or it it comes down to a PDO error.
Any help is greatly appreciated.
First, WHERE invnoc IN ? should be = ?. IN is used for matching against values in a list, not a single value.
Second, you need to provide the value from the row in the call to execute():
$detailRslt = $detailCheck->execute($row['order_id']);
Third, there's no point in using ORDER BY invnoc, since you're just matching a single invnoc value.
Fourth, you're overwriting the $count2 variable each time through the loop. You should initialize it to 0 before the loop, and then increment it, so you get the total:
$count2 += $detailCheck->rowCount();
You also don't need to prepare the query each time through the loop. The query doesn't change, so you can just prepare it once before the loop, and execute it in the loop.
Another option is to collect all the order_id values into an array, and prepare a query that matches all of them at once with IN.
$order_ids = [];
while ($row = $ordStat->fetch(PDO::FETCH_ASSOC)) {
$order_ids[] = $row['order_id'];
}
if (count($order_ids) > 0) {
$placeholders = implode(',', array_fill(0, count($order_ids), '?'));
$detailStatCheck = "
SELECT
invnoc as INVOICE,
fstatc as STATUS,
cstnoc AS DEALER,
framec AS FRAME,
covr1c AS COVER,
colr1c AS COLOR ,
extd2d AS SHIPDATE,
orqtyc AS QUANTITY
FROM GPORPCFL
WHERE invnoc IN ($placeholders)
ORDER BY invnoc asc
";
try {
$detailCheck = $DB2conn->prepare($detailStatCheck);
$detailRslt = $detailCheck->execute($order_ids);
$count2 = $detailCheck->rowCount();
echo "Matches: $count2";
} catch(PDOException $ex) {
echo "QUERY FAILED!: " .$ex->getMessage();
}
}
Your query is working fine (other than what the other answers/comments say). Your problem is actually using rowCount() on a SELECT query on a ODBC database. From the manual:
Using odbc_num_rows() to determine the number of rows available after a SELECT will return -1 with many drivers.
So if you need the count, you need to select COUNT(*) as a field and then see the value:
while($row = $ordStat->fetch(PDO::FETCH_ASSOC))
{
echo $row['order_id'] . $row['order_status'] . $row['is_placement'] . $row['date_updated'] . "\n";
$detailStatCheck = '
SELECT
COUNT(*)
FROM GPORPCFL
WHERE invnoc = ?
';
try {
$detailCheck = $DB2conn->prepare($detailStatCheck);
$detailRslt = $detailCheck->execute(['order_id']);
$count2 = $detailCheck->fetch()[0]; // <---- correct count
}
catch(PDOException $ex)
{
echo "QUERY FAILED!: " .$ex->getMessage();
}
}
How can I run a SELECT query which picks an ID which I use to delete a row in another table with that ID and later delete the row of that ID in its own table?
My code so far:
$sqel = "SELECT fldRadioCampID FROM tblradiocamp WHERE fldBestelID = '$urlIDbon' AND fldSpotnaam = '$urlDelSpotnaam'";
$result = mysql_query($link, $sqel);
if (mysql_num_rows($result) > 0) {
// output data of each row
while($row = mysql_fetch_assoc($result)) {
$sqeldelreg = "DELETE FROM tblradioregio WHERE fldRadiocampRegID=" . $row['fldRadioCampID'];
if (!mysql_query($sqeldelreg)) {
echo "Error: " . $sqeldelreg . "<br>" . mysql_error($link);
}
}
} else {
}
$sqeldel = "DELETE FROM tblradiocamp WHERE fldBestelID='$urlIDbon' AND fldSpotnaam='$urlDelSpotnaam'";
if (!mysql_query($sqeldel)) {
echo "Error: " . $sqeldel . "<br>" . mysql_error($link);
You can create procedure and call it once.
MYSQL
CREATE PROCEDURE `deleteRowById` (in urlDelSpotnaam varchar(64), in urlIDbon varchar(64) )
BEGIN
declare a int(11);
SELECT fldRadioCampID into a FROM tblradiocamp WHERE fldBestelID = urlIDbon AND fldSpotnaam = urlDelSpotnaam;
if a > 0 then
DELETE FROM tblradioregio WHERE fldRadiocampRegID=a;
DELETE FROM tblradiocamp WHERE fldRadioCampID=a;
END IF;
END
PHP
<?php
$sqel = "call deleteRowById('$urlDelSpotnaam','$urlIDbon')";
$result = mysql_query($link, $sqel);
run this query:
DELETE FROM tblradioregio
WHERE fldRadiocampRegID = (SELECT
fldRadioCampID
FROM tblradiocamp
WHERE fldBestelID = '$urlIDbon' AND fldSpotnaam = '$urlDelSpotnaam');
Note that this could also be done using a join instead of the sub-select; that's probably preferable if the subquery can return null:
DELETE FROM tblradioregio
join tblradiocamp b
on (tblradioregio.fldRadiocampRegID = b.fldRadioCampID)
WHERE b.fldBestelID = '$urlIDbon'
AND b.fldSpotnaam ='$urlDelSpotnaam';
Using legacy code which uses mysql instead of mysqli/pdo so don't worry about this, I'll update the queries for this later.
Even though my current method works, I'm positive there is a cleaner way of doing this rather than a query and 3 subqueries. I mainly want to learn how to better enhance my queries and minimizing the amount of them.
What I'm trying to do is
echo out all the data for each date with the date displayed on top
Display the count of entries for each user on that particular day next to the user
For each date, at the bottom of the above 2 bits of data, display the user/s with the highest number of entries
$query = mysql_query('SELECT * FROM entries GROUP BY DATE(dt)');
$g = 0;
while ($row = #mysql_fetch_array($query))
{
$group[$g] = date('y-m-d', strtotime($row['dt']));
echo $group[$g] . "<br />";
//display the person's name for today with their count
$dayquery = mysql_query('SELECT *, COUNT(username) as total FROM entries WHERE DATE(dt) = "'.$group[$g].'" GROUP BY username ORDER BY COUNT(username) DESC');
while ($today = #mysql_fetch_array($dayquery))
{
echo $today['first_name'] . " | " . $today['total'] . "<br />";
}
//display the highest count for today
$topquery = mysql_query('SELECT COUNT(username) as highest FROM entries WHERE DATE(dt) = "'.$group[$g].'" GROUP BY username ORDER BY COUNT(username) DESC LIMIT 1');
while ($toptoday = #mysql_fetch_array($topquery))
{
echo "Highest today: " . $toptoday['highest'] . "<br /><br />" ;
}
//display the users with the highest count for today
echo "Highest users: ";
$userstopquery = mysql_query('SELECT *, COUNT(username) as total FROM entries WHERE DATE(dt) = "'.$group[$g].'" AND COUNT(username) = "' . $toptoday['highest'] . '" AND GROUP BY username');
while ($topusers = #mysql_fetch_array($userstopquery))
{
echo $topusers['first_name'] . "<br />" ;
}
$g++;
}
The trouble I'm having is that when I try and reduce these subqueries and use MAX it will only output the highest count but not all the data for each date, which is what I need, including output of the user/s with the most amount of entries for that given day.
You could start with something like this. Note that I'm not using PHP's mysql_ API as it was deprecated 3 or 4 years ago...
require('path/to/mysqli/connection/stateme.nts');
$array = array();
$query = "
SELECT e.dt
, e.username
, COUNT(*) ttl
FROM entries e
GROUP
BY e.dt
, e.username
ORDER
BY e.dt, ttl DESC;
";
$result = mysqli_query($conn,$query);
while ($row = mysqli_fetch_assoc($result))
{
$array[] = $row;
}
print_r($array);
I already have this code:
<?php
if ($quantity == 0){
$prd_name = " ";
$colors = " ";
$sizes = " ";
$quantity = " ";
$price = " ";
$TIP = " ";
$TPA = " ";
$cost = " ";
$amount = " ";
$query ="DELETE FROM orders WHERE quantity='0'";
}
?>
But it still makes a table row entry.
What I am trying to do is when the inputed number of quantity is 0 then the table row will be deleted. Please bear with me for I'm new in php and mySQL coding.
You forgot to execute the query. It should be
$query = mysql_query("DELETE FROM orders WHERE quantity='0'");
Once run the query by removing Quotes to 0 If it's a number
<?php
if($quantity==0)
{
$query = "DELETE FROM orders WHERE quantity = 0 ";
mysql_query($query);
}
?>
<?php
if($quantity==0)
{
$query="Delete from orders where quantity=0";
mysql_query($query);
}
?>
I have a MySQL database called "bookfeather" with several tables that contain list books. Under each table, each book has a given number of votes. The PHP code below allows the user to enter in a book title ($entry), and then returns the total number of votes that book has in all tables ($sum).
How could I use PHP to make a 2-column, 25-row table that lists the 25 books in the database with the highest value for $sum (in descending order)?
Thanks in advance,
John
mysql_connect("mysqlv10", "username", "password") or die(mysql_error());
mysql_select_db("bookfeather") or die(mysql_error());
// We preform a bit of filtering
$entry = strip_tags($entry);
$entry = trim ($entry);
$entry = mysql_real_escape_string($entry);
$result = mysql_query("SHOW TABLES FROM bookfeather")
or die(mysql_error());
$table_list = array();
while(list($table)= mysql_fetch_row($result))
{
$sqlA = "SELECT COUNT(*) FROM `$table` WHERE `site` LIKE '$entry'";
$resA = mysql_query($sqlA) or die("$sqlA:".mysql_error());
list($isThere) = mysql_fetch_row($resA);
$isThere = intval($isThere);
if ($isThere)
{
$table_list[] = $table;
}
}
//$r=mysql_query("SELECT * , votes_up - votes_down AS effective_vote FROM `$table[0]` ORDER BY effective_vote DESC");
if(mysql_num_rows($resA)>0){
foreach ($table_list as $table) {
$sql = "SELECT votes_up FROM `$table` WHERE `site` LIKE '$entry'";
$sql1 = mysql_query($sql) or die("$sql:".mysql_error());
while ($row = mysql_fetch_assoc($sql1)) {
$votes[$table] = $row['votes_up'];
$sum += $row['votes_up'];
//echo $table . ': "' . $row['votes_up'] . " for $entry from $table\"<br />";
}
}
}
else{
print "<p class=\"topic2\">the book \"$entry\" has not been added to any category</p>\n";
}
//within your loop over the DB rows
//$votes[$table] = $row['votes_up'];
//afterwards
if($sum>0){
print "<table class=\"navbarb\">\n";
print "<tr>";
print "<td class='sitenameb'>".'<a type="amzn" category="books" class="links2b">'.$entry.'</a>'."</td>";
print "</tr>\n";
print "</table>\n";
//echo "<p class=\"topic3\">".''.$entry.''. "</p>\n";
echo "<p class=\"topic4\">". number_format($sum) . ' votes in total.'."</p>\n";
Try something like this. All of this hasn't been tested so please add comments for changes. I'll work with you to get the code right.
// After getting your array of tables formated like
$tableArray = array("`tableA`", "`tableB`", "`tableC`");
// create a table statement
$tableStatement = implode(", ", $tableArray);
// create a join statement
$joinStatement = "";
for ($i = 1; $i < count($tableArray); $i++) {
if ($joinStatement != "")
$joinStatement .= " AND ";
$joinStatement .= $tableArray[0] . ".site = " . $tableArray[$i] . ".site"
}
$firstTable = $tableArray[0];
$sql = "SELECT SUM(votes_up) FROM " . $tableStatement . " WHERE " . $joinStatement . " AND " . $firstTable . ".site LIKE '" . $entry . "' GROUP BY " . $firstTable . ".site ORDER BY SUM(votes_up) DESC";
Edit --------
I now realize that the query above won't work perfectly because votes_up will be ambiguous. Also because you probably want to be doing joins that grab records that are only in one table. I think the concept is the right direction even though the query may not be perfect.
You can do something like
$selectStatement = "SUM(tableA.votes_up) + SUM(tableB.votes_up) as total_votes_up"
I did something like this recently. In your database, you'll have to rename each field to a corresponding book name.php like (TaleofTwoCities.php). Now on your page that will display the vote results, you'll need to include some php files that will drive the database query on each load. I called mine "engine1.php" and "engine2.php." These will do all your sorting for you.
$query1 = mysql_fetch_row(mysql_query("SELECT url FROM pages ORDER BY counter DESC
LIMIT 0,1"));
$query2 = mysql_fetch_row(mysql_query("SELECT url FROM pages ORDER BY counter DESC
LIMIT 1,1"));
$query3 = mysql_fetch_row(mysql_query("SELECT url FROM pages ORDER BY counter DESC
LIMIT 2,1"));
and so on.. then..
$num1 = "$query1[0]";
$num2 = "$query2[0]";
$num3 = "$query3[0]";
That part sorts your listings by the number of votes from highest to lowest, with url, in your case, being the name of the books(remember you want it to end in .php - you'll see why in a second), and counter being the field that logs your votes.
Make your second engine.php file and add something like this:
$vquery1 = mysql_fetch_row(mysql_query("SELECT counter FROM pages WHERE
url='book1.php'"));
$vquery2 = mysql_fetch_row(mysql_query("SELECT counter FROM pages WHERE
url='book2.php'"));
$vnum1 = "$vquery1[0]";
$vnum2 = "$vquery2[0]";
and so on... Until you get to 25 for both this and engine 1.
Now, in your results page, after you put in the require_once(engine.php) and require_once(engine2.php) at the start of your body, start an HTML table. You only want two columns, so it'll be something like..
<table border=1 cellspacing=0 cellpadding=0>
<tr>
<?php include $num1; ?>
</tr>
<tr>
<?php include $num2; ?>
</tr>
And so on... By naming your field with "book1.php" and including the engines, $num1 will change to a different .php file depending on votes from high to low. Now all you have to do is make small php files for each book like so - no headers or anything because you're inserting it into the middle of html code already:
<td style="width:650px;"><center><img src="images/book1.jpg" alt="" border="none"
/></a></center></td>
<td style="width:150px;">Votes: <?php echo $vnum1;?></td>
And there you have it. A code that will dynamically give you results from high to low depending on the number of votes each book has.