-1

I have a query statement like this-

$result4 = mysqli_query($connection3, "UPDATE Users SET SortedOrder= (((SortedOrder+$currentTokenArray[2])+(SortedOrder+$currentTokenArray[3]))/2) where WaitLessNumber=$partner_id AND TokenNumber in (".implode(',',$sequenceArray).")");

What I want to do is make the index of $currentTokenArray[2] and $currentTokenArray[3] dynamic like $currentTokenArray[$i+2] and $currentTokenArray[$i+3] respectively where $i will take consecutive values like 1,2,3,4,5,...

So in first iteration it will compute

SortedOrder= (((SortedOrder+$currentTokenArray[2])+(SortedOrder+$currentTokenArray[3]))/2)

, in 2nd iteration it will compute

SortedOrder= (((SortedOrder+$currentTokenArray[3])+(SortedOrder+$currentTokenArray[4]))/2)

and so on

Is there a way to make this happen?

Note: The consecutive sequence 1,2,3,4,... is also available in the TokenNumber column of the table as given in the above query.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • You could compute the whole thing first and then make the query. There is no actual need to put the whole formula inside the query. Even the `imlode` can be done ahead of quering. Also using [Prepared Statemens](https://websitebeaver.com/prepared-statements-in-php-mysqli-to-prevent-sql-injection) is a good idea. I will be able to put up a working examle way later, in about 12 hours at least – Eugene Anisiutkin Feb 21 '20 at 07:02
  • Thank you..I will try these suggestions. If you can include the way to solve the dynamic indexing problem in your working example, it will be very helpful. Thanks again :) – Anubhav Sen Feb 21 '20 at 07:08
  • I hope that maybe someone will put a working example sooner, because as I said, I will have free spare time for testing in about 12 hours – Eugene Anisiutkin Feb 21 '20 at 07:41
  • Yeah no problem at all..take your time. – Anubhav Sen Feb 21 '20 at 07:55
  • Please clarify your input and your exact desired output from that input. Please provide a dbfiddle demo link that clearly states your data schema (just export from your phpmyadmin and import into the demo page. If you are saying 1,2,3,4 5 -- tell us exactly how your sample data should look after all of the updating is done. – mickmackusa Feb 23 '20 at 20:44

1 Answers1

-1

This is a very rough outline of achieving desired result. When I wrote this I made a lot of assumptions, which might prove wrong. code might require tweaking.

For example you have to use actual real data for connection. SortedOrder, currentTokenArray, partner_id and $sequenceArray variables have to come from somewhere.

Also the biggest aasumption currentTokenArray is an array of fixed length, globally. The code has to be tweaked for dynamic currentTokenArray.

I tried to put as much comments as I could.

<?php

// Update. A better error reporting setup

// Turn on displaying errors
ini_set('display_errors', 1);
// Set reporting to everything.
ini_set('error_reporting', E_ALL);
// Make Mysqli trow exceptions instead of warnings.
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

/** I assume SortedOrder has to come from somewhere also, for testing purposes it's set to 0.
    However this is not really correct, SortedOrder can be defined anywhere,
    probably somewhere at global scope, but that is an assumption.
    The functions are not really needed, but I will leave them because it might be easier to understand
    where arrays come from and what sizes they are.
    Also you can always replace the redundant generation with some actual code for getting values
*/
function getToken() {
  $token = array(); // Creating example array for holding the data

  // Filling the array with some data
  for($i=0; $i<10; ++$i) {
    array_push($token, $i); //Here we add an element to the end of the array.
  }
  return $token;
}
function getSequenceArr() {
  $sequenceArray = array(); // Creating example array for holding the data

  // Filling the array with some data
  for($i = 30; $i < 40; ++$i) {
    array_push($sequenceArray, $i); //Here we add an element to the end of the array
  }
  return $sequenceArray;
}

$SortedOrder = 0;

/** In reality this should also be somewhere else. At the include file, or even the config file.
    For testing purposes.
*/
// Connect to database, use actual data for host, username, password and database name
$conn = mysqli_connect("127.0.0.1", "username", "pass", "database");

// I assume token has to come from somewhere
$currentTokenArray = getToken();

// sequenceArray has also to come from somewhere.
$sequenceArray = getSequenceArr();

// We only have to implode array once. Result is a string.
$imploded = implode(", ", $currentTokenArray);
echo "$imploded</br>";

// partner_id comes from somewhere, for example purposes it is set to one. I am assuming partner_id is number
$partner_id = 1;

// Make placeholders for numbers
$in    = str_repeat('?,', count($currentTokenArray) - 1) . '?';
$types = str_repeat('d', count($currentTokenArray));
// This is where param binding comes in. We put ? to places where binding will occur. Explanation sucks, but I suck at good explaining.
// Docs shed more light on it. As it was pointed out we only need to do it once
$query = "UPDATE Users SET SortedOrder = ? where WaitLessNumber = ? AND TokenNumber IN ($in)";

$stmt = $conn->prepare($query); // Preparing the query

// We can't iterate using foreach as we have to stop before the last element in the array.
for($i = 0; $i < count($currentTokenArray)-2; $i++) {
  $token = $currentTokenArray[$i]; // Get current token. I am assuming here token is a number as it is used in calculations.
  $SortedOrder = ((($SortedOrder+$currentTokenArray[$i])+($SortedOrder+$currentTokenArray[$i+1]))/2);
  echo "$SortedOrder</br>";

  // Binding values. Operator ... is arcument unpacking
  $stmt->bind_param('dd'.$types, $SortedOrder, $partner_id, ...$currentTokenArray);
  $stmt->execute();
  printf("%d Rows updated.</br>", $stmt->affected_rows); // Check how much rows were updated;
}

$stmt->close(); // Close statement

$conn->close(); // Close connection

The implementation of storing SortedOrder sucks a bit also. The value exists only when the script is running. To keep it when the script is not running But that's the easiest way it can be done.

I you want to keep the value of SortedOrder between two scripts running either save it to database or even plain text file

  • Please read: [Should we ever check for mysqli_connect() errors manually?](https://stackoverflow.com/q/58808332/1839439) – Dharman Feb 21 '20 at 15:48
  • Thanks and yes I am saving the SortedOrder in the database. Actually, I am doing this so that I can display the rows in a particular order. It's something like this: Whenever a token is marked as 'A', that particular row moves 3 places down in the front-end page. Everytime when the page reloads the SortedOrder column values is copied from TokenNumber column and then the SortedOrder column value for all the rows marked as 'A' is computed separately and displayed by 'ORDER BY SortedOrder'. – Anubhav Sen Feb 21 '20 at 19:23
  • @Dharman As I said it's a very rough outline, and this can be tweaked, reporting mysqli errors as PHP exeptions takes time to setup, I should have added the link at least – Eugene Anisiutkin Feb 22 '20 at 07:55
  • @eugene What do you mean it takes time. It's only one line of code globally. – Dharman Feb 22 '20 at 09:25
  • 1
    A slight update considering php error reporting. Thee lines only, but I have seen some php setups where all three lines a required. – Eugene Anisiutkin Feb 22 '20 at 12:39
  • FYI: PHP has a [`range()`](https://www.php.net/manual/en/function.range.php) function. It could replace your 2 functions. – Dharman Feb 22 '20 at 22:31
  • `$imploded` will not work. It is a string, not a list of values. – Dharman Feb 22 '20 at 22:34
  • 1
    `$currentTokenArray.size()` is not a valid PHP syntax. Use `count()` instead. – Dharman Feb 22 '20 at 22:35
  • 1
    What is the point in preparing the same query in a loop over an over again? – Dharman Feb 22 '20 at 22:37
  • @Dharman I fixed the size() and prepare errors. I'll have to disagree about the functions. I know they can be replaced, but I had easily replaceable code and easily movable code in mind when I wrote them. Even the loop can be used for say json parsing. `range()` is very good, not very adaptable though – Eugene Anisiutkin Feb 23 '20 at 17:36
  • Are you sure you fixed it? I don't see any improvement. Did you try this code on your machine to see if it works? – Dharman Feb 23 '20 at 20:11
  • @Dharman I must have been blind or spent too much time doing C++. Fixed the count again. I am wondering why `$imploded` shouldn't work though? I can't bind a string like that? – Eugene Anisiutkin Feb 23 '20 at 20:31
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/208372/discussion-between-eugene-anisiutkin-and-dharman). – Eugene Anisiutkin Feb 23 '20 at 20:35
  • 2
    I am pretty confident that this answer does not work -- at least due to the implosion. – mickmackusa Feb 23 '20 at 20:38
  • `$SortedOrder` appears to be completely detached from the table data. To perform the calculation in advance, you'd need to fetch it first. Maybe I misunderstand the requirements. – mickmackusa Feb 23 '20 at 20:47
  • @mickmackusa I am working on fixing this thing. Conserning $SortOrder I have no Idea. OP stated it's a separate value kept somewhere in Database. – Eugene Anisiutkin Feb 23 '20 at 20:50
  • 2
    This question is probably not ready to receive answers then. It is important to differentiate between questions that should be answered and questions that should be closed instead. – mickmackusa Feb 23 '20 at 20:53
  • I agree I should not have answered, considering it was not working. But what done is done. I think I fixed all existing problems and it does work. Doesn't probably get desired result as Initial data in Db and db setup is unknown. The point was however to show that the desired calculations could be done, and they do not really depend on array length – Eugene Anisiutkin Feb 23 '20 at 21:26
  • I did something like this and it's working as of now: function build_sql($noOfRows,$data,$partner_id,$currentTokenArray,$sequenceArray){ $data2=$data+2; $data3=$data+3; if($data3<=($noOfRows-1)) { $sql="UPDATE Users SET SortedOrder=(($currentTokenArray[$data2]+$currentTokenArray[$data3])/2) where WaitLessNumber=$partner_id AND TokenNumber = $data "; } else { $maxToken=max($currentTokenArray)+0.1; $sql="UPDATE Users SET SortedOrder=$maxToken where WaitLessNumber=$partner_id AND TokenNumber = $data "; } return $sql; – Anubhav Sen Feb 24 '20 at 15:07
  • Also I am calling the function like this: foreach ($sequenceArray as $value){ $qry=build_sql($t_r,$value,$partner_id,$currentTokenArray,$sequenceArray); $result4 = mysqli_query($connection3, $qry); } – Anubhav Sen Feb 24 '20 at 15:09
  • Yes his code didn't work initially..and I also realized that $currentTokenArray.size() will give a syntax error but I am good enough to replace that with count function. I really don't get why people like to downvote stuffs on stackoverflow so much. Atleast he gave me an idea on breaking up the query..and I eventually found something that's working even though it may be inefficient. In my opinion even wrong or partially correct answers to my questions which gives me an idea on how I can proceed is better than people who're more keen on criticizing. No offense to anyone.. – Anubhav Sen Feb 24 '20 at 15:15
  • @AbhishekDas The downvotes were well deserved. Code was broken in at least tree separate places. The error checking, the binding values and the dammed count. And you really should use prepared statements – Eugene Anisiutkin Feb 24 '20 at 15:53
  • Yeah I should, but the thing is I am not comfortable with this style of code much so I first make it work using this less secure format and then once it's working I convert them into prepared statements. Thing is I'm a beginner and this is an internship project where I faced this problem. And thanks for mentioning it. – Anubhav Sen Feb 24 '20 at 16:36