I am trying to update MySQL table with results extracted from another table using a while loop but its only updating the last result set.
here is the code
$qa=$db->query("SELECT *, (acq_subudget.RemBal-order_items.total_cost) AS rama FROM order_items, acq_subudget WHERE invoice_num='$ordnumber_update' AND acq_subudget.id=order_items.disc");
while($qa_data=$qa->fetch(PDO::FETCH_ASSOC))
{
set_time_limit(0);
$account_remaining=$qa_data['rama'];
$account_name=$qa_data['acq_subudget.disc'];
$account_id=$qa_data['id'];
$qa_update=$db->exec("UPDATE `acq_subudget` SET RemBal='$account_remaining' WHERE id='$account_id'");
}
i am using pdo
you are using fetch instead of fetchAll, fetch only gets the next row from the result set
As an aside, you can probably do this in a single statement without needing a loop:-
UPDATE acq_subudget
INNER JOIN order_items
ON acq_subudget.id = order_items.disc
SET acq_subudget.RemBal = acq_subudget.RemBal-order_items.total_cost
WHERE acq_subudget.invoice_num='$ordnumber_update'
Related
I have a function that is designed to copy a product with all attributes with help of sql querys. My problem is to return new_product_id to php after completion.
If i run sql script in phpmyadmin all is working.
If i run sql script with php function all is working.
What i need help with is how to assign mysql-set-variable: #new_product_id from last query to php variable that I want to return.
----- sql query ------
CREATE TEMPORARY TABLE tmptable SELECT * FROM product WHERE id='19' AND site_id='1';
UPDATE tmptable SET id = 0,parent_id='19',status_id='1',name_internal=concat('NEW ',name_internal);
INSERT INTO product SELECT * FROM tmptable;
SET #new_product_id = LAST_INSERT_ID();
DROP TABLE tmptable;
CREATE TEMPORARY TABLE tmptable SELECT * FROM product_abcd WHERE product_id='19' AND site_id='1';
UPDATE tmptable SET product_id = #new_product_id,id=0;
INSERT INTO product_abcd SELECT * FROM tmptable;
DROP TABLE tmptable;
CREATE TEMPORARY TABLE tmptable SELECT * FROM product_efgh WHERE product_id='19' AND site_id='1';
UPDATE tmptable SET product_id = #new_product_id,id=0;
INSERT INTO product_efgh SELECT * FROM tmptable;
DROP TABLE tmptable;
(Here is more correct SQL insert statements)
SELECT #new_product_id AS new_product_id;
----- sql query ------
----- php function (not complete)------
This function is working making a new copy of product, code below is not complete but works so please only focus on multiquery part.
//return 0 for fail or new product_id (!=0) for success
public function copyProduct($data){
$res=0;
//if something, build sql-query as
$sql="sql from above";
//if we have a query to run
if(!empty($sql)){
//this is multi query, use correct function
if ($this->connect()->multi_query($sql) === TRUE) {
//loop it
while ($this->connect()->more_results()){
$result=$this->connect()->next_result();
}//while more results
}//if multiquery ok
return $res;
}//end function copy
----- php function (not complete)------
above code works, i get a nice copy of product with
result =0 for fail and
result 1 for success, (this works)
How i would like it to work is
result= 0 for fail and
result= new_product_id for success
so i can redirect user to the newly created product and therefore save user one click.
Results from query, same from phpmyadmin as from php (all good so far, no incorrect querys at this time)
Mysql returned empty results (no rows) (create temporary table)
1 row affected (update tmpt table)
1 row insert (insert into product)
mysql returned emtpy result (set $new_product_id)
mysql returened empty results (drop tmp table)
mysql returned empty result (create temporary table)
mysql x row affected (update tmp table)
mysql x row affected (insert into table)
mysql returned empty results (drop table tmptable)
mysql returned empty results (create temporary table)
.... N.....
last query "showing rows 0-0 ( 1 total) (select #new_product_id)
new_product_id=25
What have I tried?
I placed the select variable as my final query, i thought it was smart only check last query and assign variable there, but i failed due to php mysqli fetch_assoc is not possible on non object.
so next up was not so bright, i know i have 16 results from mysql and i only need the result from one of them, but anyway i places this inside multiquery
----- php function (not complete)------
This function is working making a new copy of product, NOT WORKING assigning new_product_id
//return 0 for fail or new product_id (!=0) for success
public function copyProduct($data){
$res=0;
//if something, build sql-query as
$sql="sql from above";
//if we have a query to run
if(!empty($sql)){
//this is multi query, use correct function
if ($this->connect()->multi_query($sql) === TRUE) {
//loop it
while ($this->connect()->more_results()){
//insert,update,drop will return false even if sql is ok, this would be sufficient for us now
if ($result = $this->connect()->store_result()) {
$row = $result->fetch_assoc();
if(isset($row["new_product_id"])){
//new return value of newly copied product
$res=$row["new_product_id"];
$result->free();
}
}
$result=$this->connect()->next_result();
}//while more results
}//if multiquery ok
return $res;
}//end function copy
----- php function (not complete)------
Checking other questions on stackoverflow recommended sending multiple normal querys, this seems like a bad solution when multi_query exists.
checking php library for multiquery did me no good, i cant understand how it works, as many others pointed out the documentation seems like a copy from another function.
Remember that multi_query() sends a clump of SQL queries to MySQL server but waits for the execution of only the first one. If you want to execute SQL using multi_query() and get only the result of the last query ignoring the previous ones then you need to perform a blocking loop and buffer the results into PHP array. Iterate over all results waiting for MySQL to process each query and once MySQL responds there are no more results you can keep the last fetched result.
For example, consider this function. It sends a bunch of concatenated SQL queries to the MySQL server and then waits for MySQL to process each query one by one. Every result is fetched into PHP array and the last available array is returned from the function.
function executeMultiQueryAndGetOnlyLastResult(mysqli $mysqli):array {
$mysqli->multi_query('
SELECT "a";
SELECT 2;
SELECT "val";
');
$values = [];
do {
$result = $mysqli->use_result();
if ($result) {
// process the results here
$values = $result->fetch_all();
$result->free();
}
} while ($mysqli->next_result()); // next_result will block and wait for next query to finish on MySQL server
$mysqli->store_result(); // Needed to fetch the error as exception
return $values;
}
Obviously it would be much easier to send each query separately to MySQL instead. multi_query() is very complicated and has very limited use. It can be useful if you have a number of SQL queries which you cannot execute separately via PHP, but most of the time you should be using prepared statements and send each query separately.
Another one bites the dust, I gave up and defined an array of sql querys from 0 to 14 and run it as mysqli->query() instead. Thank you all for comments and your time.
You could try using .multi_query() for all the queries in your operation except the last one, the SELECT that returns the id you want. Then run that SELECT as a single query.
This is a robust solution to your problem: #-variables belong to MySql connections and persist for the lifetimes of those connections.
And, it makes for clean and predictable operation of your software. When you need a result set returned to your program, use a single query.
Function render makes website 500% slow! Can anyone fix that please ?
Someone told me :
because it sends a database request on each iteration of the loop (it's not the only problem with this chunk of code but it's the most taxing one)
Yes I understand what that means. His way is:
you need to get all of the data before you start building the menu,
then you just insert the data instead of requesting more data on each
iteration
But i don't know how i must do it!
<?php
$menu_html='';
function render_menu($parent_id,$actmenuid)
{
$obj = new Database();
$con = $obj->dbconnectt();
global $menu_html;
$result=mysqli_query($con, "select * from tbl_menu where parent_id='$parent_id'");
if(mysqli_num_rows($result)==0) return;
if($parent_id==0){
$menu_html.='<ul class="topnav">';
}else{
$menu_html.='<ul>';
}
while($row=mysqli_fetch_array($result)) {
$childnum = $obj->recordcount("SELECT * FROM tbl_menu WHERE parent_id='".$row['id']."'");
if($childnum == 0){
$linkvalue='/category/'.$row['id'].'.html';
} else{
$linkvalue='#';
}
if($row['id']==$actmenuid && $actmenuid !=NULL){
$actv='class="active"';
}else{
$actv='';
}
$menu_html.='<li '.$actv.'>'.$row['title'].'';
render_menu($row['id'],$actmenuid);
$menu_html.='</li>';
}
$menu_html.='</ul>';return $menu_html;
}
if($isDsh==false){
echo render_menu(0,$actmenuid);
}
?>
Depending on how many records you have, try removing this query from inside the loop since it's running for every record on the first query.
$childnum = $obj->recordcount("SELECT * FROM tbl_menu WHERE parent_id='".$row['id']."'");
Change it a single query like this where it returns counts for each parent idea, and place it outside of the loop:
$parentcount = mysqli_query($con, ("SELECT parent_id, count(*) FROM tbl_menu GROUP BY parent_id");
There may be other issues, so please post the database structure and number of records that you're working with too.
Don't make recursive queries.
Having "more than 1000" rows is not too big. You can simply call everything from the table into php, then perform the recursive html build in php this will have a memory overhead, but far less processing overhead because you only ever make one trip to the db.
Alternatively (when your db table is prohibitively large), you should avoid gathering rows unnecessarily by adding a new column. The new column will store all "descendants" for the respective row when the row is INSERTed or update it when it is UPDATEd. Then you only need to reference this column when needing to call specific rows. In other words, do the recursive processing only once (when writing to the db) AND not when needing to display the data. This will, again, produce a finite result set in one query which can then be recursively traversed to build the desired output.
basically you need to do what #spudly has suggested.
But there is a small catch in his solution which depending on the number of the rows in yous tbl_menu table you may use a big chunk of memory to fetch all the records.
you can optimise it more with using his solution but changing the query to:
select
parent_tbl_menu.id,
count(child_tbl_menu.id) as cnt
from
tbl_menu as parent_tbl_menu
left join
tbl_menu as child_tbl_menu
on parent_tbl_menu.id = child_tbl_menu.parent_id
where
parent_tbl_menu.parent_id = ?
group by
parent_tbl_menu.id
This way you will only fetch the child records of a specific parent.
And please consider using prepared statements as your code has sql injection vulnerability.
Connect (from PHP to MySQL) only once for the entire web page.
Don't put a SELECT inside a loop if you can do all the work in a single SELECT, such as with a JOIN. (Exception: A "hierarchical" table needs the nested SELECT. Exception to the exception: MySQL 8.0 and MariaDB 10.2 can do it with a "recursive CTE".)
Don't fetch all the columns (SELECT *) when all you want it is a recordcount. Instead, SELECT COUNT(*) ... and use the number returned.
1000 of anything is probably excessive for a web page. Re-think the UI.
Im trying to set a variable using sprintf via a Join Query, then update each time this appears in the table using the ID loaded into the query.
The update works fine if I use a slightly different query but one that gives an identical set of results, so have come to the conclusion Im doing something silly.
Here is a selection below:
//below is a simpler version of what I would like to work with the update
$sql=sprintf("SELECT `test`.`id` FROM `test` JOIN `test2` ON (test.agent=test2.user) WHERE `test`.`type`='new' AND `test2`.`note` = 'p';
//this is what works, even though the output (list of test.id) is identical to above
$sql=sprintf("SELECT `id` FROM `test` WHERE `test`.`type`='new' AND `agent`='test.user';
//here is my update that works with the second select
if($ref_id = mysql_one_data($sql)){
$updateSQL= sprintf("UPDATE `test` SET `type`='testdata', `priority`=%s, `note`=%s WHERE `id`=%s;",SQLVal('100', "int"),SQLVal($note, "text"),SQLVal($ref_id, "int"));
$result = mysql_query($updateSQL) or die(mysql_error());
$processed=TRUE; $result="updated";
$count_converted++;
}
Any ideas? I'm at a total loss! As I said both queries give 100% the same output, so the variable produced should be the same right? and so if one update works when it finds a corresponding value the other should too.
I'm using a SELECT query to obtain a variable using mysql_fetch_assoc. This then puts the variable into an UPDATE variable to put the returned value back into the database.
If I hard code the value, or use a traditional variable and it goes in just fine, but it doesn't work when using a value previously retrieved from the database. I've tried resetting the array variable to my own text and that works.
$arrgateRetrivalQuery = mysql_query(**Select Query**);
$arrGate = mysql_fetch_assoc($arrgateRetrivalQuery);
$arrivalGateTest = $arrGate['gatetype'];
$setGateAirportSQL = "UPDATE pilots SET currentgate = '".$arrivalGateTest."' WHERE pilotid = '".$pilotid."'";
$setGateAirportQuery = mysql_query($setGateAirportSQL);
// Close MySQL Connection
mysql_close($link);
This will just make the field to update have nothing in it, however whenever I remove the variable from the SELECT to one I define, array or not, it will work.
Hope this is clear enough. Thanks in advance.
Is arrivalGateTest a number or a string? How did you try to put another value in the query? If you are sure the previous query returns a value, try to write: $setGateAirportSQL = "UPDATE pilots SET currentgate = '$arrivalGateTest' WHERE pilotid = '$pilotid'";.
Just change your sql to inlcude a subquery.
You could use the following general syntax:
UPDATE pilots SET currentgate = (SELECT gate FROM airport WHERE flight='NZ1') WHERE pilotid='2';
which is demonstrated on this fiddle
This saves the extra query and more accurately describes what you are trying to achieve.
WARNING - test it carefully first!
I have pulled in the data from a mysql database using select * with the intention of using the data several times without doing repeated sql enquiries using WHERE.
Using this data I am extracting rows that contain a search element using
while($row=mysql_fetch_array($query_result)){ <<<if match add to new array>>> }
As there are thousands of rows this is taking a longer time than I want.
I am trying to use:
$row=mysql_fetch_array($query_result);
$a = array_search($word_to_check, $row);
echo $a;
This extracts the correct sql headings but not the row number. What I want to achieve is
if $word is found in mysql_fetch_array($query_result) the add the row where it was found into the new array for processing.
Any thoughts? Thanks in advance.
Don't use mysql_* functions they are depracated. Use mysqli or pdo instead.
It's not wise to search in array of mysql results in php while it can be done in mysql. Let's say you have table and you want to find all numbers in number column that are greater than 5
SELECT FROM table_name WHERE number>5
to find text you can use simple clause
SELECT FROM table_name WHERE name = 'username'
You can also create more complex conditions.
From MYSQL manual:
WHERE clause, if given, indicates the condition or conditions that rows must satisfy to be selected. where_condition is an expression that evaluates to true for each row to be selected. The statement selects all rows if there is no WHERE clause
Check this link
If you want to limit the query to only once, fetch all the results into temporary array and do the search from it like below
<?php
$all_rows=array();
$match_rows=array();
$i=0;
$limit=100000;
while($row=mysql_fetch_array($query_result)){
$all_rows[]=$row;
if($i % $limit == 0){ // this part only functions every 100,000 cycles.
foreach($all_rows as $search_row){
if(array_search($word_to_check, $search_row)
$match_rows[]=$search_row;
}
$all_rows=array();//reset temporary array
}
$i++;
}
//This solution assumes the required word can be found in mulitple columns