i am try to update a mysql table with a PHP instance query.
but I do not know how to put the query correctly or whether there is a logical part it works specified side mysql or if i can do with php.
i get the data from a web form with 2 field the ID(It is the autoincrementable ID in MySQL) and a input with the new order.
Update Case 1: Change Order Update Data
ID=3
Imput=5
Original table 1
+--------+---------+
| ID | Order |
+--------+---------+
| 1 | 1 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 10 |this have a Hole from last registre order need preserve
| 8 | 11 |
+--------+---------+
Table
+--------+---------+
| ID | Order |
+--------+---------+
| 1 | 1 |
| 2 | 2 |
| 3 | 5 |Updated
| 4 | 6 |Updated
| 5 | 7 |Updated
| 6 | 8 |Updated
| 7 | 12 |Update, preserve and continue the hole
| 8 | 13 |Update, and Continue if more record
+--------+---------+
Update Case 2: Inserting a new record and modify the order.
ID=2
Imput=4
Original table 2
+--------+---------+
| ID | Order |
+--------+---------+
| 1 | 1 |
| 7 | 10 |this have a Hole from last registre order need preserve
| 8 | 11 |
+--------+---------+
Table
+--------+---------+
| ID | Order |
+--------+---------+
| 1 | 1 |
| 2 | 4 |record Inserted
| 7 | 10 |preserve no need update
| 8 | 11 |
+--------+---------+
I need some cycles, but do not know what conditions apply.
basics sorry for my example but I am not very expert
Update 1 Legancy
<?php
#Get Values from input Dinamical:
# $i_txt_1 = ID
# $i_txt_3 = New Order
# Attention: this is not the correct syntax for PHP, they are guidelines on what to do at every step, and that must be taken into account for the creation of the string of update.
foreach ($_POST as $key => $value){
${$key} = trim(addslashes(strip_tags($value)));
}
#collector output message
$psmg = '';
#statement prepared for the query updater
$stmtpreUP ="";
#save this variable the current date using some specific function.
$DateUD;
#We keep the variable that is the form that represents the ID
$ID = $i_txt_1;
#first condition
1. search the database if the ID exists we receive the form.
result 0{
throw new Exception You can not modify a nonexistent parameter. Search before Change
}
#second condition
2. if order is the same that the current order display MSG
{
$psmg.='<br>Update was not carried out in the Order';
}
#third condition
3. if check if it exists, any record or ID, with the order comes from the form.
result 0{
update: Create a direct update using the new order and id.
}else{
#Important Step : detecting whether an increase or decrease in the order
4. $GViD = $i_txt_3 - order;
if ($GViD < 0){
#in case is decreasing the order
$stmtpreUP .="UPDATE Table SET Order= $i_txt_3, DateUD= DateUD WHERE ID = $i_txt_1"; #String update for the ID target
#Generate the string updater for the following rows, contemplating that, if a decrease in these rows ID target should be avoided.
5.
GET "SELECT ID, Order FROM Table WHERE Order >= ".$i_txt_3." ORDER BY Order ASC";
$count = $i_txt_3; #need a counter
#Cicle to generate Update String
6.
while ($datos = mysqli_fetch_array($Get)){
#condition to ignore the target ID and update only up to the target ID range, avoid overuse of resources
if($datos['ID']!==$ID AND $datos['ID']<$ID ){
$idUD = $datos['ID'];
$count = ++$count;
$neworder = $count;
#concatenation to the Update String
$stmtpreUP .= "UPDATE table SET Order = ".$neworder.", DateUD ='".$DateUD."' WHERE ID ='{$idUD}';";
}
}
}else{
#in case is Increase the order
$stmtpreUP .="UPDATE Table SET Order= $i_txt_3, DateUD= DateUD WHERE ID = $i_txt_1"; #String update for the ID target
#Generate the string updater for the following rows, contemplating that, if a decrease in these rows ID target should be avoided.
7.
GET "SELECT ID, Order FROM Table WHERE Order >= ".$i_txt_3." ORDER BY Order ASC";
$count = $i_txt_3; #need a counter
#Cicle to generate Update String
8.
while ($datos = mysqli_fetch_array($Get)){
#condition to ignore the target ID and update all the next Order for all the table to preserver spaces into order
if($datos['ID']!==$ID){
$idUD = $datos['ID'];
$count = ++$count;
$neworder = $count;
#concatenation to the Update String
$stmtpreUP .= "UPDATE table SET Order = ".$neworder.", DateUD ='".$DateUD."' WHERE ID ='{$idUD}';";
}
}
}
}
#Run the update of all the statement
9. #function to run mutiple statement updates.
BDupdateM($stmtpreUP);
$psmg.='Datos Actualizado Correctamente';
10. output all MSG
echo $psmg;
?>
Why would you want to make something like that man, you are approaching it the wrong way IMO such a thing will be so expensive (performance wise).
If you want to ORDER BY ID, then by Order you just need to make a SELECT statement like
SELECT * FROM table ORDER BY id,order
<?php
#Get Values from input Dinamical:
# $i_txt_1 = ID
# $i_txt_3 = New Order
# Attention: this is not the correct syntax for PHP, they are guidelines on what to do at every step, and that must be taken into account for the creation of the string of update.
foreach ($_POST as $key => $value){
${$key} = trim(addslashes(strip_tags($value)));
}
#collector output message
$psmg = '';
#statement prepared for the query updater
$stmtpreUP ="";
#save this variable the current date using some specific function.
$DateUD;
#We keep the variable that is the form that represents the ID
$ID = $i_txt_1;
#first condition
1. search the database if the ID exists we receive the form.
result 0{
throw new Exception You can not modify a nonexistent parameter. Search before Change
}
#second condition
2. if order is the same that the current order display MSG
{
$psmg.='<br>Update was not carried out in the Order';
}
#third condition
3. if check if it exists, any record or ID, with the order comes from the form.
result 0{
update: Create a direct update using the new order and id.
}else{
#Important Step : detecting whether an increase or decrease in the order
4. $GViD = $i_txt_3 - order;
if ($GViD < 0){
#in case is decreasing the order
$stmtpreUP .="UPDATE Table SET Order= $i_txt_3, DateUD= DateUD WHERE ID = $i_txt_1"; #String update for the ID target
#Generate the string updater for the following rows, contemplating that, if a decrease in these rows ID target should be avoided.
5.
GET "SELECT ID, Order FROM Table WHERE Order >= ".$i_txt_3." ORDER BY Order ASC";
$count = $i_txt_3; #need a counter
#Cicle to generate Update String
6.
while ($datos = mysqli_fetch_array($Get)){
#condition to ignore the target ID and update only up to the target ID range, avoid overuse of resources
if($datos['ID']!==$ID AND $datos['ID']<$ID ){
$idUD = $datos['ID'];
$count = ++$count;
$neworder = $count;
#concatenation to the Update String
$stmtpreUP .= "UPDATE table SET Order = ".$neworder.", DateUD ='".$DateUD."' WHERE ID ='{$idUD}';";
}
}
}else{
#in case is Increase the order
$stmtpreUP .="UPDATE Table SET Order= $i_txt_3, DateUD= DateUD WHERE ID = $i_txt_1"; #String update for the ID target
#Generate the string updater for the following rows, contemplating that, if a decrease in these rows ID target should be avoided.
7.
GET "SELECT ID, Order FROM Table WHERE Order >= ".$i_txt_3." ORDER BY Order ASC";
$count = $i_txt_3; #need a counter
#Cicle to generate Update String
8.
while ($datos = mysqli_fetch_array($Get)){
#condition to ignore the target ID and update all the next Order for all the table to preserver spaces into order
if($datos['ID']!==$ID){
$idUD = $datos['ID'];
$count = ++$count;
$neworder = $count;
#concatenation to the Update String
$stmtpreUP .= "UPDATE table SET Order = ".$neworder.", DateUD ='".$DateUD."' WHERE ID ='{$idUD}';";
}
}
}
}
#Run the update of all the statement
9. #function to run mutiple statement updates.
BDupdateM($stmtpreUP);
$psmg.='Datos Actualizado Correctamente';
10. output all MSG
echo $psmg;
?>
Related
My A table stored all update of my web and V table stored which update viewed by user.
Now I want to create a SELECT statement that not fetch table A's which
id's date that id's of table V user_id=session id.
Case 1: To fetch all data from table A I used:
$id = 5, 10, 15; (for example)
$j = mysqli_query($dbh,"SELECT * FROM A WHERE `id`='".$id."' ORDER BY date DESC");
Case 2: Now select all ids where user_id = session id {If found any id reduce from case 1 fetch}
$myid = 50; ($session->id)
$p = mysqli_query($dbh,"SELECT post_id FROM V WHERE `post_id`='".$id."' AND `user_id` ='".$myid."'")
Table A:
id | from_id | to_id | date
---------------------------
5 |
10 |
15 |
20 |
Table V:
post_id | user_id
-----------------
5 | 45
15 | 50 (see: this is my id)
From above example I want fetch only ids 5 , 10 data where 15 reduce for match user_id = session id.
I don't fully understand what you want as the English isn't perfect. ;)
However, I'm certain what you want is a JOIN. See: https://dev.mysql.com/doc/refman/5.0/en/join.html
I have a table of store items with their price.
I'm trying to write a mysql query that pulls a number of items (between 3 and 6) at RANDOM, with the TOTAL value of all items within $20 of a value chosen by the user.
Any idea's on how to accomplish this?
Thanks in advance!
EDIT*** so far here is what I have. The big issue is that sum(price) takes the sum of ALL items. The secondary issue is having the "LIMIT" be random, but I can eventually have php pick a random number between 3 and 6 prior to running the query.
SELECT item,price,sum(price)
FROM items
WHERE sum(price) BETWEEN ($value-10) AND ($value+10)
ORDER BY rand() LIMIT 6
I can't think of a good way to do this in an SQL query without joining your items table on itself multiple times, which would lead to combinatorial explosion as the number of items in the table grows.
I've worked up a solution in PHP that breaks your items into price groups. Consider the following table:
+----+--------------------+-------+
| id | item | price |
+----+--------------------+-------+
| 1 | apple | 10.5 |
| 2 | banana | 1.85 |
| 3 | carrot | 16.22 |
| 4 | donut | 13.33 |
| 5 | eclair | 18.85 |
| 6 | froyo | 26.99 |
| 7 | gingerbread | 12.15 |
| 8 | honecomb | 50.68 |
| 9 | ice-cream-sandwich | 2.44 |
| 10 | jellybean | 2.45 |
| 11 | kitkat | 2.46 |
| 12 | lollipop | 42.42 |
+----+--------------------+-------+
http://sqlfiddle.com/#!9/0d815
First, break the items into Price Groups based on the random number of items (between 3 and 6 in your case). The Price Group Increment will be determined by the variance in price ($20.00) divided by the number of items being selected. This ensures that you will not go outside of your variance. Here is an example for a group of 4 items:
PRICE_GROUP_INCREMENT = VARIANCE / NUMBER_ITEMS
PRICE_GROUP_INCREMENT = 20 / 4 = 5
SELECT Count(`id`) AS `item_count`,
Round(`price` / 5) `price_group`
FROM `items`
WHERE `price` <= 35
GROUP BY `price_group`
ORDER BY `price_group` ASC;
Result set:
+------------+-------------+
| item_count | price_group |
+------------+-------------+
| 4 | 0 |
| 2 | 2 |
| 2 | 3 |
| 1 | 4 |
+------------+-------------+
Next, we can search through the result set to find a combination of price groups that equal the target price group. The target price group is determined by your target price divided by the price group increment. Using our example above, let's try to find 4 items that add up to $35.00 with a $20.00 variance.
TARGET_PRICE_GROUP = round(TARGET_PRICE / PRICE_GROUP_INCREMENT)
TARGET_PRICE_GROUP = round($35.00 / $5.00) = 7
Searching through the result set, we have can get to a target price group of 7 with these groups of 4 items:
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 0 ORDER BY rand() ASC LIMIT 2;
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 4 ORDER BY rand() ASC LIMIT 1;
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 3 ORDER BY rand() ASC LIMIT 1;
or
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 0 ORDER BY rand() ASC LIMIT 1;
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 3 ORDER BY rand() ASC LIMIT 1;
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 2 ORDER BY rand() ASC LIMIT 2;
To speed up finding a random, suitable combination of queries, I wrote a recursive function that randomly weights each price group based on the number of items in it, then sorts it. This speeds things up because the function returns as soon as it finds the first solution. Here's the full PHP script:
<?php
function rand_weighted($weight, $total){
return (float)mt_rand()*(float)$weight/((float)mt_getrandmax()*(float)$total);
};
//you can change these
$targetPrice = 35.00;
$numProducts = rand(3,6);
$maxVariance = 20.00;
$priceGroupIncrement = $maxVariance / $numProducts;
$targetPriceGroupSum = (int)round($targetPrice/$priceGroupIncrement, 0);
$select = "SELECT COUNT(`id`) AS `item_count`, ROUND(`price`/{$priceGroupIncrement}) `price_group`";
$from = "FROM `items`";
$where = "WHERE `price` <= {$targetPrice}";
$groupBy = "GROUP BY `price_group`";
$orderBy = "ORDER BY `price_group` ASC"; //for readability of result set, not necessary
$sql = "{$select} {$from} {$where} {$groupBy} {$orderBy}";
echo "SQL for price groups:\n{$sql};\n\n";
//run your query here and get the result set
//here is a sample result set
//this assumes $targetPrice = 35.00, $numProducts=4, and $maxVariance=20.00
$numProducts = 4;
$priceGroupIncrement = 5;
$targetPriceGroupSum = 7;
$resultSet = array(
array('item_count'=>4, 'price_group'=>0),
array('item_count'=>2, 'price_group'=>2),
array('item_count'=>2, 'price_group'=>3),
array('item_count'=>1, 'price_group'=>4),
);
//end sample result set
$priceGroupItemCount = array();
$priceGroupWeight = array();
$total = 0;
//randomly weight price group based on how many items are in the group
foreach ($resultSet as $result){
$priceGroupItemCount[$result['price_group']] = $result['item_count'];
$total += $result['item_count'];
}
foreach ($resultSet as $result){
$priceGroupWeight[$result['price_group']] = rand_weighted($result['item_count'], $total);
}
//recursive anonymous function to find a match
$recurse = function($priceGroupWeight, $selection=array(), $priceGroupSum=0) use ($priceGroupItemCount, $total, $numProducts, $targetPriceGroupSum, &$recurse){
//sort by random weighted value
arsort($priceGroupWeight);
//iterate through each item in the $priceGroupWeight associative array
foreach ($priceGroupWeight as $priceGroup => $weight){
//copy variables so we can try a price group
$priceGroupWeightCopy = $priceGroupWeight;
$selectionCopy = $selection;
$priceGroupSumCopy = $priceGroupSum + $priceGroup;
//try to find a combination that adds up to the target price group
if (isset($selectionCopy[$priceGroup])){
$selectionCopy[$priceGroup]++;
} else {
$selectionCopy[$priceGroup] = 1;
}
$selectionCount = array_sum($selectionCopy);
if ($priceGroupSumCopy == $targetPriceGroupSum && $selectionCount == $numProducts) {
//we found a working solution!
return $selectionCopy;
} else if ($priceGroupSumCopy < $targetPriceGroupSum && $selectionCount < $numProducts) {
//remove the item from the price group
unset($priceGroupWeightCopy[$priceGroup]);
//if there is still remaining items in the group, add the adjusted weight back into the price group
$remainingInPriceGroup = $priceGroupItemCount[$priceGroup] - $selectionCopy[$priceGroup];
if ($remainingInPriceGroup > 0){
$remainingTotal = $total - count($selection);
$priceGroupWeightCopy[$priceGroup] = rand_weighted($remainingInPriceGroup, $remainingTotal);
}
//try to find the solution by recursing
$tryRecursion = $recurse($priceGroupWeightCopy, $selectionCopy, $priceGroupSumCopy);
if ($tryRecursion !== null){
return $tryRecursion;
}
}
}
return null;
};
$selection = $recurse($priceGroupWeight);
if ($selection===null){
echo "there are no possible solutions\n";
} else {
echo "SQL for items:\n";
foreach ($selection as $priceGroup => $numberFromPriceGroup){
$select = "SELECT `items`.*";
$from = "FROM `items`";
$where = "WHERE ROUND(`price`/{$priceGroupIncrement}) = {$priceGroup}";
$orderBy = "ORDER BY rand() ASC";
$limit = "LIMIT {$numberFromPriceGroup}";
$sql = "{$select} {$from} {$where} {$orderBy} {$limit}";
echo "$sql;\n";
}
}
This algorithmic approach should perform much better than a pure SQL Query-based solution, especially once your items table grows.
You'll need to use a HAVING clause -
SELECT item, price, sum(price) as total_price
FROM items
GROUP BY item
HAVING total_price BETWEEN ($value-10) AND ($value+10)
ORDER BY rand() LIMIT 6
Here is an example and here is another example
In this case the sum is always going to be the total of each item (using GROUP BY) which is great if you only have one of each item. If you have more than one of each the sum is going to total all of those items together in the GROUP BY. Based on your original description it is the second query that you're looking for where a customer will be able to see random products within a price range.
It would be best if you provided a table schema (perhaps using SQL Fiddle) and then showed us examples of what you want the results to be.
my idea is like this 'using sql variables'
Note: id not PK
1st query `select #newvalues := (id - coalesce((select sum(minus) from tbl_name t2 where t2.id < t.id), 0)) from tbl_name t;`
2nd query. `update tbl_name set ab = #newvalues;`
could i get all the rows of #newvalues even though it is just a "select query variable"? because at the moment I could only get the last value of it which is 5.
#newvalues ID *not Primary key
9 | -----------> 9 |
8 | -----------> 8 |
7 | -----------> 7 |
6 | -----------> 6 |
5 | -----------> 5 |
*transfer the row values of #newvalues to the column ID.
First, you would need to get the row into an array in order to loop through it. To do so perform a query and store the results in a variable, then we will use the mysqli_fetch_array() function to turn the query into an array.
$idQuery = "SELECT * FROM table";
$idResult = mysqli_query(/*your database connection*/, $idQuery);
Now for the loop.
while ($row = mysqli_fetch_array($idResult)) {
$query = "UPDATE table SET ID = NewId WHERE id = " . $row['id'];
mysqli_query(/*your database connection*/, $query); }
This should work.
My table:
-----------------------
| id: | data: |
|---------------------|
| 1 | a |
| 20 | b |
| 546 | c |
-----------------------
I want to store the data in an array from last inserted row (id is auto incremented) to first.
$sth = $dbh->query('SELECT * FROM mytable');
$data = array();
while ($row = $sth->fetch(PDO::FETCH_ASSOC))
{
array_push($data, $row);
}
return $data;
What can I add to the query in order to loop through the table from bottom to top?
I tried variations of ORDER BY but they didn't work, I'm missing something.
Change MySQL statement to be
SELECT * FROM 'mytable' ORDER BY 'id' DESC
or reverse the array using PHPs reverse array function
return array_reverse($data);
Get records by descending order
use following query
SELECT * FROM mytable order by id desc
where id is the auto increment id of your table
There have been a few similar problems here on SO, but I had already implemented my way; Thought this is far from what would be expected "good"; The problem is that I have a list, you can drag & drop, though if one drags 1 element from position to position 50, 49 elements need to get updated (this would be 49 queries) just to save 1 action; Now to not do this, I saved a list and save the list to mysql;
+---------+------------+-----------+
| user_id | project_id | user_sort |
+---------+------------+-----------+
| 1 | 2 | 3,1,2 |
+---------+------------+-----------+
This has the advantage, I only need to update 1 line; The issue however is when user returns, I need to do 2 queries (select user_sort, and select all id's); and use PHP in between to explode(user_sort); most unclean and prolly slow.
Is there a better way to do this ?
if one drags 1 element from position to position 50, 49 elements need
to get updated (this would be 49 queries) just to save 1 action
That is not true, you can update all 49 rows in 2 queries:
$id = 10; // moved element
$old_pos = 1;
$new_pos = 50;
// elements between old and new position
if ($new_pos > $old_pos) {
$sql1 = "
UPDATE my_table
SET user_sort=user_sort-1
WHERE user_sort > $old_pos
AND user_sort <= $new_pos";
} else {
$sql1 = "
UPDATE my_table
SET user_sort=user_sort+1
WHERE user_sort >= $old_pos
AND user_sort < $new_pos";
}
// moved element
$sql2 = "UPDATE my_table SET user_sort=$new_pos WHERE id=$id";