How to read and update table row by row sql and php? - php

I have a database where I want to read a table row by row and then for each row I want to update a cell. I have written the below code but is there a better way of doing this ? Better way I mean it takes less time than my code.
Here is my code :
$List = 'some text...';
$SQL = "SELECT * FROM TABLE";
$res = mysqli_query($database, $SQL);
while($row = mysqli_fetch_assoc($res)){
if(strpos($List,$row['name']) !== false){
mysqli_query($database, "UPDATE TABLE SET `yes`=1 WHERE name='".$row['name']."'");
}else{
mysqli_query($database, "UPDATE TA SET `yes`=0 WHERE name='".$row['name']."'");
}
}

That approach is not the best one, the idea of SQL is to manage and be able to do that in a more efficient way. Instead of iterating each row and executing total rows +1 queries you can do only 2 queries and update the information.
for Example:
-- Update all to 0
UPDATE TABLE SET `yes`=0 ;
-- Update the one on the list to 1
UPDATE TABLE SET `yes`=1 WHERE name in ('value1','value2','value3');
This approach could save you a lot of execution time and be more efficient event on very large datasets.

i have 2 solution here
Solution 1 :
Copy the table and perform the update and rename the orginal table and also rename copy 1 table to original 1
table_1 copy to table_2
perform the operation on table_2
then rename table_1 to bkp_table_1
then rename table_2 to table_1
Solution 2
with the user select insert the data in new table which you what to update.

Related

MySql Duplicate entries with auto updating context sensitive relations in PHP

Is there any possibility to duplicate specific entries by auto updating context sensitive relations?
Given a table 'table1' like:
My goal is to duplicate all entries with categoryId 42 while updating parentId if neccessary:
id is an auto incremented column and parentId is used to identify relations between the entries.
Currently I'm inserting them one by one, selecting the old data and managing the logic for the parentId in PHP.
//Thats simplified what I do ($conn is a Zend_Db_Adapter_Abstract)
$rows = $conn->fetchAll("SELECT * FROM table1 WHERE categoryId = 42 ORDER BY parentId ASC");
$newIds = [];
foreach($rows as $row){
if(array_key_exists($row['parentId'],$newIds))
$row['parentId'] = $newIds[$row['parentId']];
else
$row['parentId'] = null;
$conn->query("INSERT INTO table1 (parentId,info,categoryId) VALUES (?,?,?)",[$row['parentId'],$row['info'],$row['categoryId']]);
$newId = $conn->lastInsertId('table1');
$newIds[$row['id']] = $newId;
}
I'm stuck with this because I need the lastInsertedId of the new element to set the new parentId for the next one.
But I'm experiencing this to be pretty slow (in relation to one single query which contains the logic).
Is there any possibility to give a query some kind of incremental element sensitive logic? Or have you any suggestions on how to fasten this up?
Any help appreciated! :)
You are not showing any code. I guess you use mysqli_insert_id() to get the last inserted ID. Maybe you can do something with MAX(ID)+1.
Something like:
INSERT INTO table1
SELECT MAX(ID)+1,
info,
categoryId
FROM
table1
WHERE .............. -- the conditions to retreive the parent

SQL - Delete row based on number of rows in another table

How would I go about deleting a row from the table 'subjects' that has a primary id 'subject_id' based on the number of rows in another table named 'replies' that uses a 'subject_id' column as a reference.
Example in pseudo code:
If ('subject' has less than 1 reply){
delete 'subject'}
I don't know much about SQL triggers so I have no clue if I would be able to incorporate this directly in the database or if I'd have to write some PHP code to handle this...
To delete any subjects that have had no replies, this query should do the trick:
DELETE s.* FROM subjects AS s
WHERE NOT EXISTS
(
SELECT r.subject_id
FROM replies AS r
WHERE r.subject_id = s.subject_id
);
Demo: DB Fiddle Example
One of the MySQL gurus will need to weigh in on whether or not you can do this directly, but in PHP you could...
$query = "SELECT subject_id FROM subjects WHERE subject='test'";
$return = mysqli_query($mysqli, $query);
$id = mysqli_fetch_assoc($return);
$query = "SELECT reply_id FROM replies WHERE subject_id='".$id[0]."'";
$return = mysqli_query($mysqli, $query);
if(mysqli_num_rows($return) < 1){
$query = "DELETE FROM subjects WHERE subject_id='1'";
$return = mysqli_query($mysqli, $query);
}
This example assumes the "subject" is unique. In other words, SELECTing WHERE subject='test' will only ever return one subject_id. If you were doing this as a periodic cleaning, you would grab all the subject_id values (no WHERE clause) and loop through them to remove them if no replies.
You can achieve this in one query by selecting all (unique) subject-ids from the replies table, and delete all subjects that doesn't have a reply in there. Using SELECT DISTINCT, you don't get the IDs more than once (if a subject has more than one reply), so you don't get unnecessary data.
DELETE FROM subjects
WHERE subject_id NOT IN (SELECT DISTINCT subject_id FROM replies)
Any subject that doesn't have a reply should be deleted!
So you want to delete all subjects with no replies:
DELETE FROM subjects WHERE subject_id NOT IN
(SELECT subject_id FROM replies);
I think this is what you want...

Update mySQL table if row from another table is certain value

UPDATE table1 SET row1 =CONCAT( row1, 'word1, word2')
I want to add a condition to the query above.
I'm looking to add text values to row1 on table1, which already contains some texts, the query above does the trick, but additionally to that, I need to add a condition. I have another table called "table2", with a column, let's say "row2" that equals to "1". I need to run the query above IF row2 in table2 equals to 1.
I'm running the query directly on PHP MyAdmin
Thanks in advance.
$query = "SELECT `row2` FROM `table2`";
$res = mysqli_query($query);
$row = mysqli_fetch_array($res);
if($row['row2'] == 1)
{
//run your update table code: UPDATE table1 SET row1 =CONCAT( row1, 'word1, word2')
}

How to handle/optimize thousands of different to executed SELECT queries?

I need to synchronize specific information between two databases (one mysql, the other a remote hosted SQL Server database) for thousands of rows. When I execute this php file it gets stuck/timeouts after several minutes I guess, so I wonder how I can fix this issue and maybe also optimize the way of "synchronizing" it.
What the code needs to do:
Basically I want to get for every row (= one account) in my database which gets updated - two specific pieces of information (= 2 SELECT queries) from another SQL Server database. Therefore I use a foreach loop which creates 2 SQL queries for each row and afterwards I update those information into 2 columns of this row. We talk about ~10k Rows which needs to run thru this foreach loop.
My idea which may help?
I have heard about things like PDO Transactions which should collect all those queries and sending them afterwards in a package of all SELECT queries, but I have no idea whether I use them correctly or whether they even help in such cases.
This is my current code, which is timing out after few minutes:
// DBH => MSSQL DB | DB => MySQL DB
$dbh->beginTransaction();
// Get all referral IDs which needs to be updated:
$listAccounts = "SELECT * FROM Gifting WHERE refsCompleted <= 100 ORDER BY idGifting ASC";
$ps_listAccounts = $db->prepare($listAccounts);
$ps_listAccounts->execute();
foreach($ps_listAccounts as $row) {
$refid=$row['refId'];
// Refsinserted
$refsInserted = "SELECT count(username) as done FROM accounts WHERE referral='$refid'";
$ps_refsInserted = $dbh->prepare($refsInserted);
$ps_refsInserted->execute();
$row = $ps_refsInserted->fetch();
$refsInserted = $row['done'];
// Refscompleted
$refsCompleted = "SELECT count(username) as done FROM accounts WHERE referral='$refid' AND finished=1";
$ps_refsCompleted = $dbh->prepare($refsCompleted);
$ps_refsCompleted->execute();
$row2 = $ps_refsCompleted->fetch();
$refsCompleted = $row2['done'];
// Update fields for local order db
$updateGifting = "UPDATE Gifting SET refsInserted = :refsInserted, refsCompleted = :refsCompleted WHERE refId = :refId";
$ps_updateGifting = $db->prepare($updateGifting);
$ps_updateGifting->bindParam(':refsInserted', $refsInserted);
$ps_updateGifting->bindParam(':refsCompleted', $refsCompleted);
$ps_updateGifting->bindParam(':refId', $refid);
$ps_updateGifting->execute();
echo "$refid: $refsInserted Refs inserted / $refsCompleted Refs completed<br>";
}
$dbh->commit();
You can do all of that in one query with a correlated sub-query:
UPDATE Gifting
SET
refsInserted=(SELECT COUNT(USERNAME)
FROM accounts
WHERE referral=Gifting.refId),
refsCompleted=(SELECT COUNT(USERNAME)
FROM accounts
WHERE referral=Gifting.refId
AND finished=1)
A correlated sub-query is essentially using a sub-query (query within a query) that references the parent query. So notice that in each of the sub-queries I am referencing the Gifting.refId column in the where clause of each sub-query. While this isn't the best for performance because each of those sub-queries still has to run independent of the other queries, it would perform much better (and likely as good as you are going to get) than what you have there.
Edit:
And just for reference. I don't know if a transaction will help here at all. Typically they are used when you have several queries that depend on each other and to give you a way to rollback if one fails. For example, banking transactions. You don't want the balance to deduct some amount until a purchase has been inserted. And if the purchase fails inserting for some reason, you want to rollback the change to the balance. So when inserting a purchase, you start a transaction, run the update balance query and the insert purchase query and only if both go in correctly and have been validated do you commit to save.
Edit2:
If I were doing this, without doing an export/import this is what I would do. This makes a few assumptions though. First is that you are using a mssql 2008 or newer and second is that the referral id is always a number. I'm also using a temp table that I insert numbers into because you can insert multiple rows easily with a single query and then run a single update query to update the gifting table. This temp table follows the structure CREATE TABLE tempTable (refId int, done int, total int).
//get list of referral accounts
//if you are using one column, only query for one column
$listAccounts = "SELECT DISTINCT refId FROM Gifting WHERE refsCompleted <= 100 ORDER BY idGifting ASC";
$ps_listAccounts = $db->prepare($listAccounts);
$ps_listAccounts->execute();
//loop over and get list of refIds from above.
$refIds = array();
foreach($ps_listAccounts as $row){
$refIds[] = $row['refId'];
}
if(count($refIds) > 0){
//implode into string for use in query below
$refIds = implode(',',$refIds);
//select out total count
$totalCount = "SELECT referral, COUNT(username) AS cnt FROM accounts WHERE referral IN ($refIds) GROUP BY referral";
$ps_totalCounts = $dbh->prepare($totalCount);
$ps_totalCounts->execute();
//add to array of counts
$counts = array();
//loop over total counts
foreach($ps_totalCounts as $row){
//if referral id not found, add it
if(!isset($counts[$row['referral']])){
$counts[$row['referral']] = array('total'=>0,'done'=>0);
}
//add to count
$counts[$row['referral']]['total'] += $row['cnt'];
}
$doneCount = "SELECT referral, COUNT(username) AS cnt FROM accounts WHERE finished=1 AND referral IN ($refIds) GROUP BY referral";
$ps_doneCounts = $dbh->prepare($doneCount);
$ps_doneCounts->execute();
//loop over total counts
foreach($ps_totalCounts as $row){
//if referral id not found, add it
if(!isset($counts[$row['referral']])){
$counts[$row['referral']] = array('total'=>0,'done'=>0);
}
//add to count
$counts[$row['referral']]['done'] += $row['cnt'];
}
//now loop over counts and generate insert queries to a temp table.
//I suggest using a temp table because you can insert multiple rows
//in one query and then the update is one query.
$sqlInsertList = array();
foreach($count as $refId=>$count){
$sqlInsertList[] = "({$refId}, {$count['done']}, {$count['total']})";
}
//clear out the temp table first so we are only inserting new rows
$truncSql = "TRUNCATE TABLE tempTable";
$ps_trunc = $db->prepare($truncSql);
$ps_trunc->execute();
//make insert sql with multiple insert rows
$insertSql = "INSERT INTO tempTable (refId, done, total) VALUES ".implode(',',$sqlInsertList);
//prepare sql for insert into mssql
$ps_insert = $db->prepare($insertSql);
$ps_insert->execute();
//sql to update existing rows
$updateSql = "UPDATE Gifting
SET refsInserted=(SELECT total FROM tempTable WHERE refId=Gifting.refId),
refsCompleted=(SELECT done FROM tempTable WHERE refId=Gifting.refId)
WHERE refId IN (SELECT refId FROM tempTable)
AND refsCompleted <= 100";
$ps_update = $db->prepare($updateSql);
$ps_update->execute();
} else {
echo "There were no reference ids found from \$dbh";
}

Pass PDO result to another temproary table or insert to temp table

Hello ,
$sql = "select col1 , col2 from table where id=2"; // sometimes query larger
$q = $conn->prepare($sql);
$q->execute(array_values($v));
$q->setFetchMode(PDO::FETCH_BOTH);
while($r = $q->fetch())
{
echo " $r[$i]";
}
Code is Working Fine.
Now i want To save Query Result to Another Temporary Table.
i Dont know no. of columns generated in Query result. Each time Query is different so columns and data is different. So How store that Query result to another table.
You could let MySQL do that work for you, e.g. via
CREATE TEMPORARY TABLE new_tbl SELECT * FROM orig_tbl WHERE ...
see http://dev.mysql.com/doc/refman/5.1/en/create-table.html

Categories