move a row between tables - php

I want to move a row from posts to archive.
Both tables have the same columns.
$st = $db->query("select * from posts where id = " . $id);
while ($row = $st->fetch()){
$date = $row['date']; ...
$sql = "insert into archive (date,...) values (:adate,...)";
$st = $db->prepare($sql);
$st->execute(array(
":adate" => $date, ...
$st = $db->query("delete from posts where id = " . $id);
id column is auto-increment on both tables.
Is there any shorter way to do this, because there are 14 columns on each table?

As long as the columns are of the same types and in the same order, you can do insert into archive select * from posts where id = :id. However, this will insert into archive with the same id.
MariaDB [temp]> select * from posts;
+------+-------+-------+
| id | a | b |
+------+-------+-------+
| 2 | test3 | test4 |
| 1 | test | test2 |
+------+-------+-------+
2 rows in set (0.00 sec)
MariaDB [temp]> select * from archive;
Empty set (0.00 sec)
MariaDB [temp]> insert into archive select * from posts where id = 2;
Query OK, 1 row affected (0.05 sec)
Records: 1 Duplicates: 0 Warnings: 0
MariaDB [temp]> select * from archive;
+------+-------+-------+
| id | a | b |
+------+-------+-------+
| 2 | test3 | test4 |
+------+-------+-------+
1 row in set (0.01 sec)
MariaDB [temp]>
If you want to let the id column auto-increment normally, you will have to select each column like insert into archive (date,...) select (date,...) from posts where id = :id
MariaDB [temp]> select * from posts;
+------+------+-------+
| id | a | b |
+------+------+-------+
| 1 | test | test2 |
+------+------+-------+
1 row in set (0.00 sec)
MariaDB [temp]> select * from archive;
+----+-------+-------+
| id | a | b |
+----+-------+-------+
| 2 | test3 | test4 |
+----+-------+-------+
1 row in set (0.00 sec)
MariaDB [temp]> insert into archive (a, b) select a, b from posts where id = 1;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
MariaDB [temp]> select * from archive;
+----+-------+-------+
| id | a | b |
+----+-------+-------+
| 2 | test3 | test4 |
| 3 | test | test2 |
+----+-------+-------+
2 rows in set (0.00 sec)
MariaDB [temp]>

Actually, I suggest you to use the following approach:
$ids = array(3, 7, 15, 31, 45);
$clause = implode(',', array_fill(0, count($ids), '?'));
$stmt = $mysqli->prepare('INSERT INTO Archive SELECT Field1, Field2, Field3 FROM Posts WHERE `id` IN ('.$clause.');');
call_user_func_array(array($stmt, 'bind_param'), $ids);
$stmt->execute();
$stmt = $mysqli->prepare('DELETE FROM Posts WHERE `id` IN ('.$clause.');');
call_user_func_array(array($stmt, 'bind_param'), $ids);
$stmt->execute();
The IN statement lets you avoid using a single query for every ID while the INSERT INTO statement lets you avoid performing a selection for every insertion. Overall, the performance of your process should be improved.
On the top of that, I recommend you to perform all that within a TRANSACTION, so that your tables won't get messed up if one of the two queries fails or if your server encounters a problem.

Related

order table when making an update

I have the following table where order by priority ASC
----------------------
|priority |activity |
|---------|-----------|
| 1 |act1 |
| 2 |act2 |
| 3 |act3 |
| 4 |act4 |
| 5 |act5 |
|---------|-----------|
JSON where I make an update.
Add Method but it does not work as I wish
<?php
//update.php
include_once('../include/conexion.php');
$query = "
UPDATE ACT_schedule SET ".$_POST["name"]." = '".$_POST["value"]."'
WHERE id_schedule = '".$_POST["pk"]."'";
$result=mysqli_query($conn, $query);
if ($result) {
$query2 = "UPDATE ACT_Agenda SET prioridad = CASE
WHEN prioridad >= " . $_POST['value'] . "
THEN prioridad + 1 ELSE prioridad END
WHERE id_agenda <> '" . $_POST['pk'] . "'";
mysqli_query($conn, $query2);
echo "YES";
} ?>
What I want to do is order the priority, if I update the act5 that has priority 5 to priority 1, the priority changes and that means that the priority of the act1 must change to 2 and so on until the act4 change to priority 5.
It works well if I update the last priority. But if I update the act4 to priority 1 the ones below should not be updated but they do it by adding +1 (act5 priority 5 is 6).
Something like that I would like if I update act4 to priority 1
----------------------
|priority |activity |
|---------|-----------|
| 1 |act4 |
| 2 |act1 |
| 3 |act2 |
| 4 |act3 |
| 5 |act5 |
|---------|-----------|
I hope I explained well. Greetings.
From your code it's not 100% clear which are the appropriate $_POST variables to use in the update query so here is a pure MySQL solution. First create the demo table:
CREATE TABLE agenda (`priority` int, `activity` varchar(4));
INSERT INTO agenda (`priority`, `activity`)
VALUES (1, 'act1'), (2, 'act2'), (3, 'act3'), (4, 'act4'), (5, 'act5');
SELECT * FROM agenda ORDER BY priority;
Output:
priority activity
1 act1
2 act2
3 act3
4 act4
5 act5
To update, use the following query. I have used variables #n for the new priority and #a for the activity to modify; in your PHP code you would remove the SET statements below and replace #n and #p in the update query with the appropriate $_POST values. In this example I am shifting act4 to priority 2:
SET #a = 'act4';
SET #n = 2;
UPDATE agenda SET priority = CASE WHEN priority BETWEEN #n AND (SELECT * FROM (SELECT priority FROM agenda WHERE activity=#a) a) AND activity != #a THEN priority + 1
WHEN activity = #a THEN #n
ELSE priority
END;
Now we can look at the modified table:
SELECT * FROM agenda ORDER BY priority;
Output:
priority activity
1 act1
2 act4
3 act2
4 act3
5 act5
SQLFiddle Demo
This can be achieved all inside the database. Please see the following example proof:
First the boring part where I created your table and inserted your sample data:
mysql> CREATE TABLE priority_demo (priority SMALLINT UNSIGNED, activity VARCHAR(4));
Query OK, 0 rows affected (0.06 sec)
mysql> INSERT INTO priority_demo VALUES (1, 'act1');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO priority_demo VALUES (2, 'act2'), (3, 'act3'),(4, 'act4'), (5,'act5');
Query OK, 4 rows affected (0.02 sec)
mysql> SELECT * FROM priority_demo;
+----------+----------+
| priority | activity |
+----------+----------+
| 1 | act1 |
| 2 | act2 |
| 3 | act3 |
| 4 | act4 |
| 5 | act5 |
+----------+----------+
5 rows in set (0.00 sec)
Now, as an example, I'm changing the priority of act4 (currently prio 4) to new value 2. As my example is generic then I'm gonna use internal variables for both current and new priority for the specific activity, whereas ideally instead of #activity_key and #new you'd use your php variables when constructing the query:
mysql> SET #activity_key := 'act4', #new = 2; -- variables from php
Query OK, 0 rows affected (0.00 sec)
For demo purposes I'm outputting them too:
mysql> SELECT #activity_key, #new; -- variables used below
+---------------+------+
| #activity_key | #new |
+---------------+------+
| act4 | 2 |
+---------------+------+
Ok, we're ready to act now.
First the most interesting query - the UPDATE with priority changes.
As pulling the current priority out of the database is un-necessary overhead and useless round trip, I've implemented 3rd MySQL variable here, called #cur which contains the current value, so the update query below would know if and where and what to change.
We run the 2 following queries (SET #cur ... and UPDATE ...) together as one batcho. This ensures that it's not gonna change anything if already changed:
mysql> -- both in one "batch"
-> SET #cur := (SELECT priority FROM priority_demo WHERE activity=#activity_key LIMIT 1);
-> UPDATE priority_demo SET priority=CASE
-> WHEN priority >= #new AND priority < #cur THEN priority+IF(#cur<>#new, 1,0)
-> WHEN activity = #activity_key THEN #new ELSE priority END;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 5 Changed: 0 Warnings: 0
Let's see the result:
mysql> SELECT * FROM priority_demo; -- result as is
+----------+----------+
| priority | activity |
+----------+----------+
| 1 | act1 |
| 3 | act2 |
| 4 | act3 |
| 2 | act4 |
| 5 | act5 |
+----------+----------+
5 rows in set (0.00 sec)
mysql> SELECT * FROM priority_demo ORDER BY priority; -- priority ordered view
+----------+----------+
| priority | activity |
+----------+----------+
| 1 | act1 |
| 2 | act4 |
| 3 | act2 |
| 4 | act3 |
| 5 | act5 |
+----------+----------+
5 rows in set (0.00 sec)
Even if you reran the query again, it wouldn't change anything. That's because of the IF(...) part of the UPDATE above.
EDIT: I just discovered that my answer is somewhat similar to #nicks, but that's ok, I guess, as my proposed implementation can be safely executed in a "shoot firt, ask questions later" manner ;)
I got your point... Basically you need to edit sort order numbers in your column Priority...
is your priority colum is primary ? or separate id column is there in your mysql table.. ? if separate primary id column doesn't exist.. create it and keep this priority column separate, so you can change/update sort numbers in this column....
in your ajax update script..i.e.... updatePriorityJSON.php.... you will need code somewhat like..
this is not tested.. but given as sample...
for($i=0; $i<count($_POST["priority"]); $i++) {
$query = "
UPDATE table
SET priority = '".$i."'
WHERE id = '".$_POST["id"][$i]."'";
}
more tutorial point of view, please view https://www.webslesson.info/2017/06/sorting-table-row-using-jquery-drag-drop-with-ajax-php.html?m=1
Please take care for prevention of any SQL injection through this code
After updating act5 priority to 1: (*)
UPDATE ACT_Agenda SET priority = 1 WHERE activity = 'act5';
Check to see the other records that need to be updated:
SELECT * FROM ACT_Agenda WHERE priority >= 1 AND activity <> 'act5';
Then update the priority: (*)
UPDATE ACT_Agenda SET priority = priority+1 WHERE priority >= 1 AND activity <> 'act5';
(*) last step is to implement this sql to your code

PHP - Store a SELECT Query and use it inside a INSERT query

Hi i'm having trouble using the data from a select query inside a insert query.
This is my php code -
<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbName = "arestaurant";
$ID = $_GET["Id"];
$QUANTITY = $_GET["Quantity"];
$TABLE = $_GET["Table"];
//Make connection
$conn = new mysqli($servername,$username,$password,$dbName);
// check connection
if(!$conn) {
die("Connection Failed. ".mysqli_connect_error());
}
$sql = "INSERT INTO tableorders (tableNumber,isPaid)
VALUES ('".$TABLE."','0')";
$result = mysqli_query($conn,$sql);
$y = "SELECT orderId from tableorders WHERE tableNumber='$TABLE' ORDER by orderDate DESC limit 1 offset 0 ";
$resulty = mysqli_query($conn,$y);
if ($resulty !== false) {
$value = mysqli_fetch_field($resulty);
$orderid = $value['orderId']; < -- error
}
$sqlquery = "INSERT INTO orderitems (orderId, productId, quantity)
VALUES ('".$orderid."','".$ID."','".$QUANTITY."')";
$result2 = mysqli_query($conn,$sqlquery);
?>
but im getting -
Fatal error: Cannot use object of type stdClass as array on line 30.
I have several ways in storing it and then using it again, but i can seem to find the solution.
please help?
This error its because the function mysqli_fetch_field return a object, you maybe wants read http://php.net/manual/es/mysqli-result.fetch-field.php
and this function return info of each column.
change this:
$value = mysqli_fetch_field($resulty);
$orderid = $value->orderId;
Maybe you need use: fetch_assoc
http://php.net/manual/es/mysqli-result.fetch-assoc.php
good luck
If you wants get data of column please use fetch assoc like this:
$y = "SELECT orderId from tableorders WHERE tableNumber='$TABLE' ORDER by orderDate DESC limit 1 offset 0 ";
$resulty = mysqli_query($conn,$y);
if ($resulty !== false) {
$fila = $resultado->fetch_assoc()
$orderid = $fila['orderId'];
}
The best solution is this:
https://dev.mysql.com/doc/refman/5.7/en/insert-select.html
You don't need to pull the data out to insert it back. Let the MySQL do it for you.
This is my take on the combined insert-select statement. Would you try it?
$sqlquery = "INSERT INTO orderitems (orderId, productId, quantity)
SELECT orderId, $ID, $QUANTITY from tableorders WHERE tableNumber='$TABLE' ORDER by orderDate DESC limit 1";
I drop the offset because I didn't see the purpose of it.
Here is an example:
Imagine that there is table called tasks with many rows and we want to select an id value from it and insert it into this test table together with some external values.
mysql> create table test (id int, order_id int, product_id int);
Query OK, 0 rows affected (0.09 sec)
mysql> describe test;
+------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| order_id | int(11) | YES | | NULL | |
| product_id | int(11) | YES | | NULL | |
+------------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> insert into test select id, 5, 6 from tasks order by id asc limit 1;
Query OK, 1 row affected (0.06 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from test;
+------+----------+------------+
| id | order_id | product_id |
+------+----------+------------+
| 1 | 5 | 6 |
+------+----------+------------+
1 row in set (0.00 sec)
mysql> insert into test(id, order_id, product_id) select id, 5, 6 from tasks order by id asc limit 1;
Query OK, 1 row affected (0.04 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from test;
+------+----------+------------+
| id | order_id | product_id |
+------+----------+------------+
| 1 | 5 | 6 |
| 1 | 5 | 6 |
+------+----------+------------+
2 rows in set (0.00 sec)
mysql>
I hope that it shed some lights on the possibilities of the insert-select method

Trigger- Update columns in one table on inserting in another table

So, I have 2 tables.
One is books, that has the following fields.
accno(Accession number), name(book name), status(Issued/Not Issued)
Second is total, that has the following fields.
name(book name), count(Number of books that are 'Not Issued' in the books table
I have a form that adds books in the books table, and the default status is 'Not Issued'.
I also have a form that issued books i.e. it changes the status to 'Issued'.
And I have a form that returns the books i.e. it changes the status back to 'Not Issued'.
I'm looking for a trigger that updates the count in the total table everytime the bookstable is updated. Count is the number of books that are available(Not Issued) in the books table, and it is different for different books(book names).
I am totally new to triggers. I have looked arond, but I can't seem to figure a way to implement this.
Any help is appreciated. Thank you.
Looks like its an inventory system, so every time a new book comes into the library you store the inventory number into the total table and when a book is issued against the accnum the inventory is decreased by one and then its returned its increased by one.
In this case the following trigger should do the job
delimiter //
create trigger book_available after update on books
for each row
begin
if new.status = 'Issued' then
update total set `count` = `count` - 1 where name = new.book_name ;
else
update total set `count` = `count` + 1 where name = new.book_name ;
end if ;
delimiter ;
Here is a test case
mysql> select * from books ;
+--------+-----------+------------+
| accnum | book_name | status |
+--------+-----------+------------+
| 1 | AA | Not Issued |
| 2 | AA | Issued |
| 3 | BB | Not Issued |
+--------+-----------+------------+
3 rows in set (0.00 sec)
mysql> select * from total ;
+------+-------+
| name | count |
+------+-------+
| AA | 20 |
| BB | 30 |
+------+-------+
2 rows in set (0.00 sec)
mysql> delimiter //
mysql> create trigger book_available after update on books
-> for each row
-> begin
-> if new.status = 'Issued' then
-> update total set `count` = `count` - 1 where name = new.book_name ;
-> else
-> update total set `count` = `count` + 1 where name = new.book_name ;
-> end if ;
-> end ;//
Query OK, 0 rows affected (0.13 sec)
mysql> delimiter ;
mysql> update books set status = 'Issued' where accnum = 1 ;
Query OK, 1 row affected (0.08 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from total ;
+------+-------+
| name | count |
+------+-------+
| AA | 19 |
| BB | 30 |
+------+-------+
2 rows in set (0.00 sec)
mysql> update books set status = 'Not Issued' where accnum = 1 ;
Query OK, 1 row affected (0.04 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from total ;
+------+-------+
| name | count |
+------+-------+
| AA | 20 |
| BB | 30 |
+------+-------+
2 rows in set (0.00 sec)

Simple UPDATE SQL Query

I'm doing a work for a client but since I haven't been using PHP/MySQL for a while I forgot some simple things, hope you can help me out.
I have the following SQL table:
ID (non-null, autoincrement) | credit (int)
My query should put the whole "credit" column to 0 except for the row that has the higher ID.
So I would do:
UPDATE $table SET credit = 0 WHERE... ?
Thanks in advance for any help :)
UPDATE $table SET credit = 0 WHERE ID > $ID
Will update any rows that have and ID greater than the variable $ID
If you only want to update the row with the maximum ID then use:
UPDATE $table SET credit = 0 WHERE ID = (select max(id) from $table)
Edit: As Eggyal correctly points out MySQL doesn't like a subquery on the same table as an update - but you can get around it nicely:
UPDATE $table
SET credit = 0
WHERE
credit='$credit'
AND statid='$statid'
AND userid='$userid'
AND ID = (select ID from (SELECT MAX(ID)as ID from $table) a)
And examples from my console:
mysql> select * from first;
+------+-------+
| id | title |
+------+-------+
| 1 | aaaa |
| 2 | bbbb |
| 3 | cccc |
| 4 | NULL |
| 6 | eeee |
+------+-------+
5 rows in set (0.00 sec)
mysql> update first set title='ffff' where id=(select max(id) from first);
ERROR 1093 (HY000): You can't specify target table 'first' for update in FROM clause
mysql> update first set title='ffff' where id=(select ID from (select max(id) as ID from first) a);
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from first;
+------+-------+
| id | title |
+------+-------+
| 1 | aaaa |
| 2 | bbbb |
| 3 | cccc |
| 4 | NULL |
| 6 | ffff |
+------+-------+
5 rows in set (0.00 sec)
Note: As the subquery within a subquery trick unlocks the original table, it is a good idea to run this within a transaction - if the table is unlocked from a query, it might have changed by the time it is updated - so it will be a good idea to use this type of query within a transaction.

PDO Mysql prepared statement last_insert_id returns wrong value on multi-insert?

I noticed that if I prepare a multi-insert statement and execute it into MySQL via PDO, and then request the last_insert_id, I get the first ID of the multiple inserted rows, not the last one. Specifically:
"INSERT INTO test_table (value1, value2, value3) VALUES (1, 2, 3), (1, 2, 3)";
will create these rows on an empty table:
ID value1 value2 value3
1 1 2 3
2 1 2 3
But the last_insert_id will return "1".
Is this a known issue or am I doing something wrong? Could someone verify/test/explain this? I am at a loss at what to do to get the proper last ID, save for doing an actual select which would be WAY slower.
It's correct mysql behavior
http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
mysql> USE test;
Database changed
mysql> CREATE TABLE t (
-> id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
-> name VARCHAR(10) NOT NULL
-> );
Query OK, 0 rows affected (0.09 sec)
mysql> INSERT INTO t VALUES (NULL, 'Bob');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
| 1 | Bob |
+----+------+
1 row in set (0.01 sec)
mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 1 |
+------------------+
1 row in set (0.00 sec)
mysql> INSERT INTO t VALUES
-> (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
| 1 | Bob |
| 2 | Mary |
| 3 | Jane |
| 4 | Lisa |
+----+------+
4 rows in set (0.01 sec)
mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 2 |
+------------------+
1 row in set (0.00 sec)

Categories