how to increment column value by 1 and reset every 9 rows - mysql

I'm trying to increment column value by 1 but row number 10 reset and start with 1 like that
i have like more than 600k row
I tried call all the 600k row by php and update them but i stopped and give me some error
table sample:
CREATE TABLE `s1_table_play` (
`id` int(11) NOT NULL,
`player_id` int(11) DEFAULT 1,
`play_points` varchar(20) DEFAULT '0',
`original_points` varchar(20) DEFAULT '0',
`play_type` varchar(20) DEFAULT '0',
`created_at` timestamp NULL DEFAULT current_timestamp(),
`table_id` bigint(20) DEFAULT 0,
`play_number` int(11) DEFAULT 1
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `s1_table_play` (`id`, `player_id`, `play_points`, `original_points`, `play_type`, `created_at`, `table_id`, `play_number`) VALUES
(1, 1, '200', '0', '0', '2021-07-01 10:58:00', 67667, 1);
this the field "play_number" need to updated and reset every 10 rows
thanks

I am not really clear what your data looks like or when you want to reset but a trigger might be appropriate.
DROP TABLE IF EXISTS T;
create table t
(id int, playno int);
drop trigger if exists t;
delimiter $$
create trigger t before insert on t
for each row
begin
declare n int;
set n = (select playno from t where id < new.id order by id desc limit 1);
set n = coalesce(n+ 1,1);
if n >2 then set n = 1; end if;
set new.playno = n;
end $$
delimiter ;
insert into t(id) values (1),(2),(3),(4),(5);
select * from t;
+------+--------+
| id | playno |
+------+--------+
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
+------+--------+
5 rows in set (0.001 sec)

Related

Select rows from one table and adjust the values based on rows in another table

I have a table of widgets with an ID and corresponding price. I also have a table of discounts. There can be multiple discounts per widget, each being either a fixed amount or percentage reduction. Compound discounts must be applied in the order specified by their position.
widgets
id | price
----------
1 | 10.50
2 | 2.25
3 | 15.75
discounts
id | widgetId | fixedDiscount | percentageDiscount | position
1 | 1 | 0.35 | | 1
2 | 1 | | 25 | 2
3 | 3 | | 10 | 1
Could I create a query/procedure which would select each widget and its final price, after all discounts had been applied?
With the sample data above:
- Widget 1 should have a 0.35 reduction, then further reduced by 25%. (2 discounts)
- Widget 2 should be unchanged at the original 2.25 (no discount)
- Widget 3 should have a 10% reduction (1 discount)
The only way I am aware of is to join the discounts table to the widgets table and then calculate the final price in PHP once I have all the data. However, my data is a much more complicated version of this hypothetical example. There are likely to be hundreds of widgets with many having more than a handful of discounts for the report I am trying to generate.
Sample data above can be created like so:
CREATE TABLE `widgets` (
`id` INT NOT NULL AUTO_INCREMENT,
`price` DECIMAL(5,2) NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `discounts` (
`id` INT NOT NULL AUTO_INCREMENT,
`widgetId` INT NOT NULL,
`fixedDiscount` DECIMAL(5,2) NULL,
`percentageDiscount` DECIMAL(4,2) NULL,
`position` TINYINT NOT NULL,
PRIMARY KEY (`id`),
INDEX `fk_widgets_discounts_idx` (`widgetId` ASC),
CONSTRAINT `fk_widgets_discounts`
FOREIGN KEY (`widgetId`)
REFERENCES `widgets` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE);
INSERT INTO
`widgets` (`id`, `price`)
VALUES
('1', '10.50'),
('2', '2.25'),
('3', '15.75');
INSERT INTO
`discounts` (`id`, `widgetId`, `fixedDiscount`, `percentageDiscount`, `position`)
VALUES
('1', '1', '0.35', null , '1'),
('2', '1', null, '25', '2'),
('3', '3', null, '10', '1');
The way we decided to solve this problem was by means of a MySQL function which returns the discounted price of a widget from its id.
DELIMITER $$
CREATE FUNCTION `widgetPrice`(p_widgetId INT) RETURNS decimal(5,2)
BEGIN
DECLARE v_maxPos INT;
DECLARE v_startPos INT;
DECLARE v_newPrice DECIMAL(5,2);
DECLARE v_fixedDiscount DECIMAL(5,2);
DECLARE v_percentageDiscount DECIMAL(4,2);
DECLARE v_discount DECIMAL (5,2);
SELECT MAX(position) FROM discounts WHERE widgetId = p_widgetId INTO v_maxPos;
SELECT price FROM widgets WHERE id = p_widgetId INTO v_newPrice;
SET v_startPos = 1;
WHILE v_maxPos > 0 DO
SET v_fixedDiscount = 0;
SET v_percentageDiscount = 0;
SET v_discount = 0;
SELECT fixedDiscount, percentageDiscount FROM discounts WHERE widgetId = p_widgetId AND position = v_startPos INTO v_fixedDiscount, v_percentageDiscount;
IF ( v_fixedDiscount IS NOT NULL ) THEN
SET v_discount = v_fixedDiscount;
ELSEIF ( v_percentageDiscount IS NOT NULL ) THEN
SET v_discount = v_newPrice * v_percentageDiscount / 100;
END IF;
SET v_newPrice = v_newPrice - v_discount;
SET v_maxPos = v_maxPos - 1;
SET v_startPos = v_startPos + 1;
END WHILE;
RETURN v_newPrice;
END$$
DELIMITER;
We can SELECT data as follows to retrieve each widget with its discounted price:
SELECT
id,
price,
widgetPrice(id) AS discountedPrice
FROM
widgets;
Which gives us:
id | price | discountedPrice
------------------------------
1 | 10.50 | 7.61
2 | 2.25 | 2.25
3 | 15.75 | 14.17

MySQL trigger works on one field, not on second field, in the same table

I have a MySQL database with a table inventory with multiple triggers set up to capture changes in a second table inventory_history. I'm updating two of the fields (both in a single query, and in two separate queries), and the trigger consistently works on only one of the two fields (qty but not on last_sale).
Here is the troublesome query:
UPDATE inventory SET last_sale = 321, qty = 0 WHERE id = 123;
Alternately, these query combinations don't work either:
UPDATE inventory SET last_sale = 321 WHERE id = 123;
UPDATE inventory SET qty = 0 WHERE id = 123;
Here are the table constructs and triggers:
CREATE TABLE `inventory` (
`serial_no` varchar(255) DEFAULT NULL,
`qty` mediumint(9) DEFAULT NULL,
`partid` mediumint(9) unsigned DEFAULT NULL,
`last_sale` mediumint(9) unsigned DEFAULT NULL,
`date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`id` mediumint(9) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `partid` (`partid`),
KEY `date_created` (`date_created`),
KEY `last_sale` (`last_sale`),
KEY `last_rma` (`last_return`),
KEY `last_purchase` (`last_purchase`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `inventory_history` (
`date` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`inventory_id` mediumint(9) unsigned NOT NULL,
`field_changed` enum('serial_no','qty','partid','last_sale','new') NOT NULL,
`changed_from` varchar(255) NOT NULL,
KEY `inventory_id` (`inventory_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TRIGGER `inv_new` AFTER INSERT ON `inventory`
FOR EACH ROW BEGIN
SET
#id = NEW.id,
#userid = NEW.userid,
#date = now();
INSERT INTO inventory_history VALUES (#date,#userid, #id, 'new', 'new');
END
//
DELIMITER ;
DROP TRIGGER IF EXISTS `inv_update`;
DELIMITER //
CREATE TRIGGER `inv_update` AFTER UPDATE ON `inventory`
FOR EACH ROW BEGIN
SET #userid = OLD.userid;
SET #inv_id = OLD.id;
IF (OLD.serial_no <> NEW.serial_no) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'serial_no', OLD.serial_no);
END IF;
IF (OLD.qty <> NEW.qty) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'qty', OLD.qty);
END IF;
IF (OLD.partid <> NEW.partid) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'partid', OLD.partid);
END IF;
IF (OLD.last_sale <> NEW.last_sale) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'last_sale', OLD.last_sale);
END IF;
END
//
DELIMITER ;
So again, the qty trigger works, but the last_sale does not.
I can't reproduce the problem:
mysql> DROP TABLE IF EXISTS `inventory_history`, `inventory`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `inventory` (
-> `serial_no` varchar(255) DEFAULT NULL,
-> `qty` mediumint(9) DEFAULT NULL,
-> `partid` mediumint(9) unsigned DEFAULT NULL,
-> `last_sale` mediumint(9) unsigned DEFAULT NULL,
-> `date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
-> `id` mediumint(9) unsigned NOT NULL AUTO_INCREMENT,
-> PRIMARY KEY (`id`),
-> KEY `partid` (`partid`),
-> KEY `date_created` (`date_created`),
-> KEY `last_sale` (`last_sale`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `inventory_history` (
-> `date` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-> `inventory_id` mediumint(9) unsigned NOT NULL,
-> `field_changed` enum('serial_no', 'qty', 'partid', 'last_sale', 'new') NOT NULL,
-> `changed_from` varchar(255) NOT NULL,
-> KEY `inventory_id` (`inventory_id`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.01 sec)
mysql> DELIMITER //
mysql> CREATE TRIGGER `inv_new` AFTER INSERT ON `inventory`
-> FOR EACH ROW
-> BEGIN
-> DECLARE `_id` MEDIUMINT UNSIGNED DEFAULT NEW.`id`;
-> DECLARE `_date` TIMESTAMP DEFAULT NOW();
-> INSERT INTO `inventory_history` VALUES (`_date`, `_id`, 'new', 'new');
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> DROP TRIGGER IF EXISTS `inv_update`;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> DELIMITER //
mysql> CREATE TRIGGER `inv_update` AFTER UPDATE ON `inventory`
-> FOR EACH ROW
-> BEGIN
-> DECLARE `_inv_id` MEDIUMINT UNSIGNED DEFAULT OLD.`id`;
->
-> IF (OLD.`serial_no` <> NEW.`serial_no`) THEN
-> INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'serial_no', OLD.`serial_no`);
-> END IF;
->
-> IF (OLD.`qty` <> NEW.`qty`) THEN
-> INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'qty', OLD.`qty`);
-> END IF;
->
-> IF (OLD.`partid` <> NEW.`partid`) THEN
-> INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'partid', OLD.`partid`);
-> END IF;
->
-> IF (OLD.`last_sale` <> NEW.`last_sale`) THEN
-> INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'last_sale', OLD.`last_sale`);
-> END IF;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> INSERT INTO `inventory`
-> (`serial_no`, `qty`, `partid`, `last_sale`)
-> VALUES
-> ('1', 0, 0, 321);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT
-> `serial_no`,
-> `qty`,
-> `partid`,
-> `last_sale`,
-> `date_created`,
-> `id`
-> FROM
-> `inventory`;
+-----------+------+--------+-----------+---------------------+----+
| serial_no | qty | partid | last_sale | date_created | id |
+-----------+------+--------+-----------+---------------------+----+
| 1 | 0 | 0 | 321 | 2016-11-15 00:00:51 | 1 |
+-----------+------+--------+-----------+---------------------+----+
1 row in set (0.00 sec)
mysql> SELECT
-> `date`,
-> `inventory_id`,
-> `field_changed`,
-> `changed_from`
-> FROM
-> `inventory_history`;
+---------------------+--------------+---------------+--------------+
| date | inventory_id | field_changed | changed_from |
+---------------------+--------------+---------------+--------------+
| 2016-11-15 00:00:51 | 1 | new | new |
+---------------------+--------------+---------------+--------------+
1 row in set (0.00 sec)
mysql> UPDATE `inventory`
-> SET `last_sale` = 0, `qty` = 321
-> WHERE `id` = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT
-> `date`,
-> `inventory_id`,
-> `field_changed`,
-> `changed_from`
-> FROM
-> `inventory_history`;
+---------------------+--------------+---------------+--------------+
| date | inventory_id | field_changed | changed_from |
+---------------------+--------------+---------------+--------------+
| 2016-11-15 00:00:51 | 1 | new | new |
| 2016-11-15 00:00:51 | 1 | qty | 0 |
| 2016-11-15 00:00:51 | 1 | last_sale | 321 |
+---------------------+--------------+---------------+--------------+
3 rows in set (0.00 sec)
mysql> SELECT
-> `serial_no`,
-> `qty`,
-> `partid`,
-> `last_sale`,
-> `date_created`,
-> `id`
-> FROM
-> `inventory`;
+-----------+------+--------+-----------+---------------------+----+
| serial_no | qty | partid | last_sale | date_created | id |
+-----------+------+--------+-----------+---------------------+----+
| 1 | 321 | 0 | 0 | 2016-11-15 00:00:51 | 1 |
+-----------+------+--------+-----------+---------------------+----+
1 row in set (0.00 sec)
Days later, turns out to be a simple but profound explanation (isn't it always?).
The trigger statement I used above was:
IF (OLD.last_sale <> NEW.last_sale) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'last_sale', OLD.last_sale);
END IF;
The problem with this statement is that it doesn't capture a value change from NULL to 0, for example. It only captures a value to another value. So I needed to ADD a second statement for the NULL scenarios:
IF (OLD.last_sale IS NULL AND NEW.last_sale IS NOT NULL) THEN
INSERT INTO inventory_history VALUES (now(), #userid, #inv_id, 'last_sale', OLD.last_sale);
END IF;
And all the world is right. :)

SQL - Setting a maximum number when incrementing a value by 1

I want increment difficulty by 1 but the value of difficulty should not go past 3. How do I do that?
This is my query
$query=mysqli_query($con,"UPDATE ticket
SET status = 'open',
difficulty = difficulty + 1
WHERE ticketid = '$_POST[ticketid]'")
Schema
create table ticket
( ticketid int auto_increment primary key,
status varchar(20) not null,
difficulty int not null
);
insert ticket(status,difficulty) values (0,0),(0,0); -- 2 rows
run this query a bunch of times:
update ticket
set status ='open',
difficulty=least(difficulty+1,3)
where ticketid=2;
Now look at data
select * from ticket;
+----------+--------+------------+
| ticketid | status | difficulty |
+----------+--------+------------+
| 1 | 0 | 0 |
| 2 | open | 3 |
+----------+--------+------------+
See Mysql Comparison functions
Try this:
$ticket_id = mysqli_real_escape_string($con, $_POST['ticketid']);
$query=mysqli_query($con,"UPDATE ticket
SET status = 'open',
difficulty = least(difficulty + 1,3)
WHERE ticketid = '$ticket_id'")
Note that I added ticket_id escaping to fix the SQL injection.
You can also use a if statement:
CREATE TABLE IF NOT EXISTS `ticket` (
`ticketid` int(11) NOT NULL AUTO_INCREMENT,
`status` varchar(20) NOT NULL,
`difficulty` int(11) NOT NULL,
PRIMARY KEY (`ticketid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
INSERT INTO ticket (difficulty, status) VALUES (0,0);
UPDATE
ticket
SET
`difficulty` = IF(`difficulty` < 3,`difficulty` + 1, 3)
WHERE
`ticketid`=1;
For more information have a look at https://www.ask-sheldon.com/conditions/.

How to generate a dynamic sequence table in MySQL?

I'm trying to generate a sequence table in MySQL, so that I can get unique ids from last_insert_id.
The problem is that I need multiple sequences dynamically.
At the first, I created a table:
CREATE TABLE `sequence` (
`label` char(30) CHARACTER SET latin1 NOT NULL,
`id` mediumint(9) NOT NULL DEFAULT '0',
PRIMARY KEY (`label`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
And then tried to get the number, using example from http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
UPDATE sequence SET id = LAST_INSERT_ID(id + 1) WHERE label = 'test';
SELECT LAST_INSERT_ID();
After a while I realized that I also need to generate rows for new labels safely.
So I changed this schema into:
CREATE TABLE `sequence` (
`label` char(30) CHARACTER SET latin1 NOT NULL,
`id` mediumint(9) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`label`,`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
And I simply gave up using WHERE clause to update its id.
INSERT INTO sequence (label) values ( ? )
SELECT LAST_INSERT_ID()
Is this a proper way? I want to know if there is a better solution.
The MyISAM engine will do it for you -
Table definition:
CREATE TABLE `sequence` (
`label` char(30) CHARACTER SET latin1 NOT NULL,
`id` mediumint(9) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`label`,`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Populate table:
INSERT INTO sequence VALUES ('a', NULL); -- add some 'a' labels
INSERT INTO sequence VALUES ('a', NULL);
INSERT INTO sequence VALUES ('a', NULL);
INSERT INTO sequence VALUES ('b', NULL); -- add another labels 'b'
INSERT INTO sequence VALUES ('b', NULL);
INSERT INTO sequence VALUES ('a', NULL); -- add some 'a' labels
INSERT INTO sequence VALUES ('a', NULL);
Show result:
SELECT * FROM sequence;
+-------+----+
| label | id |
+-------+----+
| a | 1 |
| a | 2 |
| a | 3 |
| a | 4 |
| a | 5 |
| a | 6 |
| b | 1 |
| b | 2 |
+-------+----+

Two primary keys & auto increment

I have a MySQL table with two fields as primary key (ID & Account), ID has AUTO_INCREMENT.
This results in the following MySQL table:
ID | Account
------------------
1 | 1
2 | 1
3 | 2
4 | 3
However, I expected the following result (restart AUTO_INCREMENT for each Account):
ID | Account
------------------
1 | 1
2 | 1
1 | 2
1 | 3
What is wrong in my configuration? How can I fix this?
Thanks!
Functionality you're describing is possible only with MyISAM engine. You need to specify the CREATE TABLE statement like this:
CREATE TABLE your_table (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
account_id INT UNSIGNED NOT NULL,
PRIMARY KEY(account_id, id)
) ENGINE = MyISAM;
If you use an innoDB engine, you can use a trigger like this:
CREATE TRIGGER `your_table_before_ins_trig` BEFORE INSERT ON `your_table`
FOR EACH ROW
begin
declare next_id int unsigned default 1;
-- get the next ID for your Account Number
select max(ID) + 1 into next_id from your_table where Account = new.Account;
-- if there is no Account number yet, set the ID to 1 by default
IF next_id IS NULL THEN SET next_id = 1; END IF;
set new.ID= next_id;
end#
Note ! your delimiter column is # in the sql statement above !
This solution works for a table like yours if you create it without any auto_increment functionality like this:
CREATE TABLE IF NOT EXISTS `your_table` (
`ID` int(11) NOT NULL,
`Account` int(11) NOT NULL,
PRIMARY KEY (`ID`,`Account`)
);
Now you can insert your values like this:
INSERT INTO your_table (`Account`) VALUES (1);
INSERT INTO your_table (`Account`, `ID`) VALUES (1, 5);
INSERT INTO your_table (`Account`) VALUES (2);
INSERT INTO your_table (`Account`, `ID`) VALUES (3, 10205);
It will result in this:
ID | Account
------------------
1 | 1
2 | 1
1 | 2
1 | 3