Reset auto_increment based on datetime column - mysql

I'm working with MySQL through phpMyAdmin. I need to reset the ID fields in one of the tables in my database, but I need to do it based on the publication date of each row. I've been looking everywhere and I can't seem to find a solution :(
The following lines of code work fine, but do not do exactly what I require based on the datetime column:
SET #count = 0;
UPDATE `table_name` SET `table_name`.`ID` = #count:= #count + 1;
So this is what I have:
+----+---------------------+
| ID | post_date |
+----+---------------------+
| 1 | 2013-11-04 20:06:28 |
| 2 | 2012-03-30 11:20:22 |
| 3 | 2014-06-26 22:59:51 |
+----+---------------------+
And this is what I need:
+----+---------------------+
| ID | post_date |
+----+---------------------+
| 1 | 2005-08-02 16:51:48 |
| 2 | 2005-08-02 16:59:36 |
| 3 | 2005-08-02 17:01:54 |
+----+---------------------+
Thanks in advance, guys :)

Try this, a simple approach though.
But you will lose all the relations to other tables since you are
resetting the PRIMARY ID Keys.
# Copy entire table to a temporary one based on the publication date
CREATE TEMPORARY TABLE IF NOT EXISTS `#temp_table` AS SELECT * FROM `wp_posts` ORDER BY `post_date`;
# Drop `ID` column from the temporary table
ALTER TABLE `#temp_table` DROP COLUMN `ID`;
# Reset the table `wp_posts` as well as its `ID`
TRUNCATE TABLE `wp_posts`;
# Exclude `ID` column in the INSERT statement below
INSERT INTO `wp_posts`(`post_author`, `post_date`, ..., `comment_count`) SELECT * FROM `#temp_table`;
# Remove the temporary table
DROP TABLE `#temp_table`;
Also see the ERD for WP3.0 below,
Ref: https://codex.wordpress.org/Database_Description/3.3

Try doing it with the following script. It selects every row of your table and orders the rows by its date ascending. Then your Update-Command will be executed within a loop.
Add the type of the ID of your table to the DECLARE-Statement and change the
field-Name in the UPDATE-Statement to your ID-Column name.
BEGIN
DECLARE col_id BIGINT;
DECLARE stepLoopDone BOOLEAN DEFAULT FALSE;
DECLARE counter INT DEFAULT 1;
DECLARE ORDER_CURSOR CURSOR FOR
SELECT id
FROM wp_posts
ORDER BY post_date ASC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET stepLoopDone = TRUE;
OPEN ORDER_CURSOR;
myLoop: LOOP
FETCH ORDER_CURSOR INTO col_id;
IF stepLoopDone THEN
LEAVE myLoop;
END IF;
/*YOUR UPDATE COMMAND*/
UPDATE wp_posts
SET id = counter
WHERE id = col_id;
/*YOUR UPDATE COMMAND*/
SET counter = counter + 1;
END LOOP;
CLOSE ORDER_CURSOR;
END

Related

Trigger needs to fire only when column value is today's date

I want to apply the trigger in database when column_value match the particular scenario like
In goal table there are fields like goal, status, start_Date, end_Date
Now I want to change the status of goal. When user enter his/her goal, he/she filled end_Date. Now I want to change the status of goal when end_Date matched to current Date
Example:-
+------+--------+--------------+-------------+
| GOAL | STATUS | START_DATE | END_DATE |
+------+--------+--------------+-------------+
| 1 | Active | 2017-07-03 | 2017-07-09 |
+------+--------+------------+---------------+
When END_DATE equals to current Date, then I want to change status 'Active' to 'Finished'
I hope I am able to understand my question.
Thanks in advance!
Body of an oracle table level trigger would look like this...
BEGIN
IF INSERTING and (:new.end_date = sysdate) THEN
:NEW.goal_status := desired_value;
ELSIF UPDATING AND (:new.end_date = sysdate) then
:NEW.goal_status := desired_value;
END IF;
End;
The logic for this is
DROP TRIGGER IF EXISTS TB;
DELIMITER //
CREATE TRIGGER TB BEFORE INSERT ON T
FOR EACH ROW
BEGIN
IF NEW.START_DT = DATE(NOW()) THEN
SET NEW.STATUS = 'YES' ;
end if;
END //
DELIMITER ;
use sandbox;
DROP TABLE IF EXISTS T;
CREATE TABLE T(GOAL INT, STATUS VARCHAR(3), START_DT DATE,END_DATE DATE);
mysql> TRUNCATE TABLE T;INSERT INTO T VALUES(1,NULL,'2017-07-06','2017-07-06');SELECT * FROM T;
Query OK, 0 rows affected (0.73 sec)
Query OK, 1 row affected (0.06 sec)
+------+--------+------------+------------+
| GOAL | STATUS | START_DT | END_DATE |
+------+--------+------------+------------+
| 1 | YES | 2017-07-06 | 2017-07-06 |
+------+--------+------------+------------+
1 row in set (0.00 sec)

MySQL: Reference current row in delete trigger

I'm having trouble referencing the current row in an AFTER DELETE trigger in MySQL. Pretend I have the following books table:
+----+------+----------+
| id | name | ordering |
+----+------+----------+
| 1 | It | 3 |
| 2 | Cujo | 1 |
| 3 | Rage | 2 |
+----+------+----------+
I want to create a trigger that will decrement all rows whose ordering value is greater than the ordering value in a row that is deleted. For example, if I do DELETE FROM books WHERE id = 2, I want the resulting table to look like:
+----+------+----------+
| id | name | ordering |
+----+------+----------+
| 1 | It | 2 |
| 3 | Rage | 1 |
+----+------+----------+
I've tried:
DROP TRIGGER IF EXISTS reorder_books_on_delete;
DELIMITER $$
CREATE TRIGGER reorder_books_on_delete
AFTER DELETE ON books
FOR EACH ROW
BEGIN
IF ordering > OLD.ordering
THEN
UPDATE books SET ordering = ordering - 1
WHERE id = id;
END IF;
END$$
DELIMITER ;
But this results in an error when I execute a DELETE on the table:
ERROR 1054 (42S22): Unknown column 'ordering' in 'where clause'
This refers to the if statement, so how do I reference the current row in an ON DELETE trigger? The column definitely does exist.
The reason why it fails is because there is no current row and hence, ordering column doesn't exist, it should be used in WHERE clause, like this:
DROP TRIGGER IF EXISTS reorder_books_on_delete;
DELIMITER $$
CREATE TRIGGER reorder_books_on_delete
AFTER DELETE ON books
FOR EACH ROW
BEGIN
UPDATE books SET ordering = ordering - 1
WHERE ordering > OLD.ordering;
END$$
DELIMITER ;
However, as per MySQL's documentation, you can't do this, it will return the following error:
SQL Error (1442): Can't update table 'books' in stored
function/trigger because it is already used by statement which invoked
this stored function/trigger.
So, you will have to run another UPDATE query after DELETE query in a single transaction to achieve this functionality.
As said by Darshan, you can't do this with a Trigger.... But, Procedure can make if for you !
DROP PROCEDURE IF EXISTS delete_book;
DELIMITER //
CREATE PROCEDURE delete_book(IN pId INT)
BEGIN
set #a = (
SELECT ordering
FROM books
WHERE id = pId
);
UPDATE books SET ordering = ordering - 1
WHERE ordering > #a;
delete from books
WHERE id = pId;
END
//
DELIMITER ;
And you just have, instead of your DELETE FROM books WHERE id = 4 to make a CALL delete_book(4);

Mysql for every n-th update to do a special update

Is it possible to do something like this with mysql?
Imagine I've update query, that runs every time user gives successful answer. Now I'd like to count updates and give +1 bonus point every fourth time...
I could just count rows and divide them by 4, but that would give me non spendable bonus points, because for every update it will get recalculated...
Is there any mysql solution to my problem?
I think you may use trigger and calculate additional bonuses when user gives successful answer.
Here is working example:
DROP TABLE IF EXISTS answer;
CREATE TABLE answer
(
id int not null auto_increment,
bonus int not null,
primary key(id)
);
DELIMITER //
CREATE TRIGGER lucky_trigger BEFORE INSERT ON answer
FOR EACH ROW BEGIN
IF MOD((SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'answer'), 4) = 0 THEN
SET NEW.bonus = NEW.bonus + 1;
END IF;
END //
DELIMITER ;
INSERT INTO answer(bonus) VALUES(1);
INSERT INTO answer(bonus) VALUES(1);
INSERT INTO answer(bonus) VALUES(1);
INSERT INTO answer(bonus) VALUES(1);
SELECT id, bonus FROM answer;
Will give you next output:
+----+-------+
| id | bonus |
+----+-------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
+----+-------+
4 rows in set (0.00 sec)

Split comma separated values from one column to 2 rows in the results. MySQL

MySQL. Two columns, same table.
Column 1 has product_id
Column 2 has category_ids (sometimes 2 categories, so will look like 23,43)
How do i write a query to return a list of product_id, category_ids, with a seperate row if there is more than 1 category_id associated with a product_id.
i.e
TABLE:
product_id | category_ids
100 | 200,300
101 | 201
QUERY RESULT: Not trying to modify the table
100 | 200
100 | 300
101 | 201
EDIT: (note) I don't actually wish to manipulate the table at all. Just doing a query in PHP, so i can use the data as needed.
Your database table implementation seems bad designed, however in your case what you need would be a reverse function of GROUP_CONCAT, but unfortunately it doesn't exist in MySQL.
You have two viable solutions :
Change the way you store the data (allow duplicate on the product_id field and put multiple records with the same product_id for different category_id)
Manipulate the query result from within your application (you mentioned PHP in your question), in this case you have to split the category_ids column values and assemble a result set by your own
There is also a third solution that i have found that is like a trick (using a temporary table and a stored procedure), first of all you have to declare this stored procedure :
DELIMITER $$
CREATE PROCEDURE csv_Explode( sSepar VARCHAR(255), saVal TEXT )
body:
BEGIN
DROP TEMPORARY TABLE IF EXISTS csv_Explode;
CREATE TEMPORARY TABLE lib_Explode(
`pos` int unsigned NOT NULL auto_increment,
`val` VARCHAR(255) NOT NULL,
PRIMARY KEY (`pos`)
) ENGINE=Memory COMMENT='Explode() results.';
IF sSepar IS NULL OR saVal IS NULL THEN LEAVE body; END IF;
SET #saTail = saVal;
SET #iSeparLen = LENGTH( sSepar );
create_layers:
WHILE #saTail != '' DO
# Get the next value
SET #sHead = SUBSTRING_INDEX(#saTail, sSepar, 1);
SET #saTail = SUBSTRING( #saTail, LENGTH(#sHead) + 1 + #iSeparLen );
INSERT INTO lib_Explode SET val = #sHead;
END WHILE;
END; $$
DELIMITER ;
Then you have to call the procedure passing the array in the column you want to explode :
CALL csv_explode(',', (SELECT category_ids FROM products WHERE product_id = 100));
After this you can show results in the temporary table in this way :
SELECT * FROM csv_explode;
And the result set will be :
+-----+-----+
| pos | val |
+-----+-----+
| 1 | 200 |
| 2 | 300 |
+-----+-----+
It could be a starting point for you ...

How to update all MySQL table rows at the same time?

How do I update all MySQL table rows at the same time?
For example, I have the table:
id | ip | port | online_status |
1 | ip1 | port1 | |
2 | ip2 | port2 | |
3 | ip3 | port3 | |
4 | ip4 | port4 | |
5 | ip5 | port5 | |
I'm planning to create cronjob and monitor some servers, but I don't know exactly how to update them all from the table at the same time. What are some examples on how to do that?
Omit the where clause:
update mytable set
column1 = value1,
column2 = value2,
-- other column values etc
;
This will give all rows the same values.
This might not be what you want - consider truncate then a mass insert:
truncate mytable; -- delete all rows efficiently
insert into mytable (column1, column2, ...) values
(row1value1, row1value2, ...), -- row 1
(row2value1, row2value2, ...), -- row 2
-- etc
;
update mytable set online_status = 'online'
If you want to assign different values, you should use the TRANSACTION technique.
The default null value for a field is "not null". So you must set it to "null" before you can set that field value for any record to null. Then you can:
UPDATE `myTable` SET `myField` = null
UPDATE dummy SET myfield=1 WHERE id>1;
You can try this,
UPDATE *tableName* SET *field1* = *your_data*, *field2* = *your_data* ... WHERE 1 = 1;
Well in your case if you want to update your online_status to some value, you can try this,
UPDATE thisTable SET online_status = 'Online' WHERE 1 = 1;
Hope it helps. :D
just use UPDATE query without condition like this
UPDATE tablename SET online_status=0;
Just add parameters, split by comma:
UPDATE tablename SET column1 = "value1", column2 = "value2" ....
see the link also
MySQL UPDATE