I have a number which is in this form : 2012-01 (2012 as current year) and 01 is just a the maximum value of a field in my database incremented by 1, and each year that number is reset to 0.
but if there are two users that try to do the same operation at the same time the value is the same for both and thus i get the same number inserted twice in my database .
I thought of creating a sequence but that requires a job that resets the sequence each year and i would prefer if there is a way to make a lock before i get the next number and
release it after an insert is done ?
Thanks.
CREATE UNIQUE INDEX index_name ON table_name (column_name);
or
ALTER TABLE table_name ADD CONSTRAINT constraint_name UNIQUE (column_name);
You don't specify where you store the field that is used as the counter. But maybe it is possible to use a SELECT FOR UPDATE statement.
Before you increment the value of your counter field by 1 you can lock that record by using a SELECT FOR UPDATE. Then update the counter.
Something like this, assuming the table has only 1 record:
SELECT *
FROM CounterTable
FOR UPDATE;
UPDATE CounterTable
SET Counter = Counter + 1;
COMMIT;
If one session (user) has done the SELECT FOR UPDATE and not yet committed or rolled back, the other session (user) doing a SELECT FOR UPDATE will block waiting to be able to get a lock. This prevents two users from getting the same number.
Related
I have a check-in / check-out system which writes for every check-in a new row in my table and updates the table when the person checks out (like checkedout = 1)
Now I'm making a new site that always shows the newest checked in person. I do it by polling and storing the highest ID on a variable on that page. In the polling I search for entries > the id i stored. It's working good so far.
But now I want to extend it and show either the latest checked in person OR the latest checked out person. How can I get the last "updated" row in my table?
You can add a column for ex. date_checked of type datetime and update it whenever something happens.
After that just select by that column.
use mysql function called mysqli_insert_id() which will give you last inserted primary key value of the table
try this:
SET #update_id := 0;
UPDATE some_table SET column_name = 'value', id = (SELECT #update_id := id)
WHERE some_other_column = 'blah' LIMIT 1;
SELECT #update_id;
More Click Here
I'm using PHP to insert groups of records into a MySQL DB.
Whenever I insert a group of records, I want to give that group a unique set ID that is incremented by 1 for each group of records in the DB.
Currently, I'm checking the latest set ID in the DB and incrementing it by 1 for each new set of records.
The thing that scares me though is what happens if I query the DB to get the latest set ID, and before I can insert a new set of records with that set ID + 1, another insert occurs on the table thus taking the set ID I was about to use?
While fairly unlikely, something like that could greatly sacrifice the integrity of the data.
What can I do to prevent such a thing from happening? Is there any way to temporarily lock the DB table so that no other inserts can occur until I have performed a SELECT/INSERT combo?
Locking the table is one option, but that approach impacts concurrency.
The approach I would recommend is that you use a separate table with AUTO_INCREMENT column, and use a separate INSERT into that table, and a SELECT LAST_INSERT_ID() to retrieve the auto_increment value.
And then use that value as the group identifier for the group of rows you insert into your original table.
The basic approach is:
LOCK TABLE foo WRITE;
SELECT MAX(id) + 1 FROM foo
INSERT ...
INSERT ...
UNLOCK TABLES;
Locking the table prevents any other process from changing the table until you explicitly unlock it.
Having said that, seriously consider just using a table with an AUTO_INCREMENT column. MySQL will do the work of maintaining unique keys wholly automatically, and then you can simply refer to those keys from your existing table.
I am having problem to update the list of id number again starting from 1,2,3,4,5. Since I have deleted few records as I was testing the sql commands. Can you please help on how to make this id column again starting from 1.
I could just the name of the id number however if I do that then when I input new record, it will again start from the previous number which was 66.
ID Name
1 A
32 B
34 C
35 D
55 E
66 F
Truncate your table first and then execute this
ALTER TABLE tablename AUTO_INCREMENT = 1
You should truncate the table to reseed it properly and not just use alter table
(tldr; it's usually better not to worry about the density or sequential order an auto-increment column.)
It is not possible1 to use an AUTO_INCREMENT to automatically fill in values less than MAX(ID).
However, the auto increment ID can be reset if existing IDs are updated. The compacting phase is required because MySQL does not allow "filling in gaps" via an auto-increment column.
Compact the existing IDs, like so:
SET #i := 0;
UPDATE t id = #i := (#i+1)
Important: Make sure that all relational usage is identified in the form of Foreign Key relations with CASCADE ON UPDATE before this is done or the data may become irreversibly corrupted.
Assign the auto-ID see to the maximum1 ID value after compacting:
ALTER TABLE t AUTO_INCREMENT = (SELECT MAX(id) FROM t)
1 Per the AUTO_INCREMENT documentation in ALTER TABLE:
You cannot reset the counter to a value less than or equal to the value that is currently in use .. if the value is less than or equal to the maximum value currently in the AUTO_INCREMENT column, the value is reset to the current maximum AUTO_INCREMENT column value plus one.
The rule means that it is not possible to set the increment ID lower than an already used ID; in addition, manually assigning a value higher will automatically raise the AUTO_INCREMENT value.
The easiest (and sometimest fastest) way is to remove column and add it back. Updating column may screw up indexes or make a mess with values. Droping whole table got no sense. But remember that if other columns refer to that ids you can damage your app.
I have a column 'updatetime' that is a timestamp ("2011-02-01 09:00:51"). For performance purposes I need to create an indexed column 'updatetime_hour' based on the hour of the timestamp.
So for example if 'updatetime' was "2011-02-01 09:00:51" then 'updatetime_hour' would be "9".
I'm trying to do this all in mysql though PHP is an option as well. 60k+ existing rows.
Thoughts?
UPDATE yourtable SET updatetime_hour=HOUR(updatetime);
Don't run this in peak hours, it will take a while. You could even run it in smaller batches - make updatetime_hour nullable and continue running this, until you get "0 rows affected":
UPDATE yourtable SET updatetime_hour=HOUR(updatetime)
WHERE updatetime_hour IS NULL LIMIT 1000;
To do this automatically each time you add or update a row, use triggers:
CREATE TRIGGER t1 BEFORE INSERT ON table
FOR EACH ROW BEGIN
SET NEW.updatetime_hour = HOUR(NEW.updatetime);
END
CREATE TRIGGER t2 BEFORE UPDATE ON table
FOR EACH ROW BEGIN
SET NEW.updatetime_hour = HOUR(NEW.updatetime);
END
I run points system on my site so I need to keep logs of different action of my users into database. The problem is that I have too many users and keeping all the records permanently may cause server overload... I there a way to keep only 10 records per user and automatically delete older entries? Does mysql have some function for this?
Thanks in advance
You can add a trigger that takes care of removing old entries.
For instance,
DELIMITER //
CREATE definer='root'#'localhost' TRIGGER afterMytableInsert AFTER INSERT ON MyTable
FOR EACH ROW
BEGIN
DELETE FROM MyTable WHERE user_id = NEW.user_id AND id NOT IN
(SELECT id FROM MyTable WHERE user_id = NEW.user_id ORDER BY action_time DESC LIMIT 10);
END//
Just run an hourly cron job that deletes the 11th - n records.
Before insert a record you could check how many the user has first. If they have >=10 delete the oldest one. Then insert the new one.
If your goal is to have the database ensure that for a given table there are never more than N rows per a given subkey (user) then the correct way to solve this will be either:
Use stored procedures to manage inserts in the table.
Use a trigger to delete older rows after an insert.
If you're already using stored procedures for data access, then modifying the insert procedure would make the most sense, otherwise a trigger will be the easiest solution.
Alternately if your goal is to periodically remove old data, then using a cron job to start a stored procedure to prune old data would make the most sense.
When you are inserting a new record for a user. Just do a query like this before (Don't forget the where-condition):
DELETE FROM tablename WHERE userID = 'currentUserId' LIMIT 9, 999999
After that you can insert new data. This keeps the data always to ten records for each user.
INSERT INTO tablename VALUES(....)
DELETE FROM Table WHERE ID NOT IN (SELECT TOP 10 ID FROM Table WHERE USER_ID = 1) AND USER_ID = 1
Clearer Version
DELETE FROM Table
WHERE ID NOT IN
(
SELECT TOP 10 ID FROM Table WHERE USER_ID = 1
)
AND USER_ID = 1