I want to generate customer ids for invoices and thus don't want to start counting from 1 for obvious reasons. In MySQL can you generate a random number that is unique?
I know about the RAND() function, but it does not guarantee uniqueness. What's the right approach for this?
Doesn't work:
INSERT INTO test (number) VALUES (FLOOR(0 + (RAND() * 9999999999)));
PS: Server side I'm using PHP and generate invoices using FPDF.
I suggest an AUTO_INCREMENT column and seed the value at 10 digits. You could have it be the only column in the table, like below, or more practically seed your invoice table id.
CREATE TABLE tablename (
id bigint unsigned not null auto_increment,
primary key(id),
auto_increment=1000000000
);
Actually, the reasons aren't that obvious unless it's simply that you don't want your customers to know there are so few that they all have one-digit IDs :-)
As an aside, the customer ID is usually generated when adding a customer rather than doing an invoice. If you meant an invoice number, that's different, but the reasoning will be the same.
Either populate the table with a dummy entry with a suitable lower ID (314159 for example) then use something like:
insert into test (number) select max(number)+1 from test
or use an auto incrementing key with a suitable starting value (again, this value is up to you but you should choose something relatively "non-round").
I've sometimes used the former for situations where I want total control over what values are assigned (including the ability to easily change them) but a more robust solution would probably be the auto-increment one.
ALTER TABLE my_invoice_table auto_increment=1000000001
Incrementing invoice numbers are fine - they only have to be unique, not random.
Related
I was developing a database in SQL Server where I was using an identity column as a seed for a primary key field. The intention was to reset the identity to 1 at the beginning of every year. This would allow us to create a PK of the Year - Identity Column.
Create Table Issues (
IssueID AS RIGHT(CONVERT(VARCHAR, Year(getdate()), 4),2) + '-' + RIGHT(REPLICATE('0', 2) +
CONVERT(VARCHAR, RecordID),3) NOT NULL PRIMARY KEY,
RecordID int Identity (1,1),.........)
The result would be
IssueID RecordID
20-001 1
20-002 2
20-003 3
21-001 1
etc....
Now I've been told we are going to use a MySQL database instead.
Can an Auto-Increment field in MySQL contain duplicate values like it can in SQL Server?
If Not, how can I do what I need to do in MySQL?
In MySQL, you can't use the default auto-increment feature for what you describe, a incrementing value that starts over per year.
This was a feature of the MyISAM storage engine years ago. An auto-increment that was the second column of a multi-column primary key would start counting from one for each distinct value in the first column of the PK. See the example under "MyISAM Notes" on this page: https://dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html
But it's considered not a good idea to use MyISAM because it does not support ACID. In general, I would find another way of solving this task. I would not use MyISAM.
In InnoDB, there's no way the table will generate a value that is a duplicate of a value currently in the table, or even a value less than the maximum value previously generated for that table. In other words, there's no way to "fill in the gaps" using auto-increment.
You can use ALTER TABLE mytable AUTO_INCREMENT=1 to reset the counter, but the value you set it will automatically advance to the max value currently in the table + 1.
So you'll have to generate it using either another table, or else something other than the MySQL database. For example, I've seen some people use memcached, which supports an atomic "increment and return counter" operation.
Another thing to consider: If you need a row counter per year, this is actually different from using MySQL's auto-increment feature. It's not easy to use the latter as a row counter. Besides, what happens if you roll back a transaction or delete a row? You'd end up with non-consecutive RecordId values, with unexplained "gaps." It's also a fact about the auto-increment feature that it guarantees that subsequent id's will be greater, but it does not guarantee to generate all values consecutively. So you'll get gaps eventually anyway.
In MySQL a table can have only one auto_increment column and this column must be a part of the primary key. See details here.
Technical workaround for your task would be creating of a table with a single auto_increment column, and you can obtain auto_increment value by inserting a record into this table and immediately calling standard MySQL function last_inser_id(). When time comes you should truncate the table - in this case the auto_increment count will be reset.
If I delete the max IDs (for example 9, 10,11) from the table, the sql will not begin from the max existing ID ! it begins with 12!
is it possible to let the sql add new id according to existing max id?
how to get the max primary key autoincrement in the table (the deleted one too)?
This code finds the existing only and not the deleted ids:
select max(id) from table1
If I delete the max IDs (for example 9, 10,11) from the table, the sql will not begin from the max existing ID ! it begins with 12 !
That is correct. There is nothing surprising or exclamation-worthy about this. That's how RDBMSes work.
1- is it possible to let the sql add new id according to existing max id ?
Not easily at all. As a matter of fact, it is so difficult, and any attempt to do it would be so tied to the particular RDBMS that you are using, (that is, so not portable,) that you are advised to not even try. That's because RDBMSes are built for highly concurrent use, so they have to be able to prevent the possibility of different clients inserting inconsistent primary key values.
2- how to get the max primary key autoincrement in the table
There really is no such thing as a "max primary key autoincrement in the table", because it may be changing at a very fast rate as someone is inserting rows into the table, so by the time your select max(id) from table1 would return a value to you, the actual max value in the database may already be different.
As the title, how to create a 9 digits number primary key which is random, unique, not repeated and from range 100000000 to 999999999?
And this method must be work on the godaddy server, seems godaddy have so many limitation.
I can only think of two reliable ways of creating unique numbers.
Use a systematic process, such as auto-incrementing, where you now the numbers are unique.
Store generated numbers in a table.
You want random numbers, so the first method could be applied using a pseudo-random number generator. But the second is probably simpler to implement.
It goes something like this:
create table numbers (
numberid int auto_increment primary key,
n varchar(10) not null unique
);
Then you need to create numbers using a loop. Do the following until it succeeds:
insert into numbers (n)
select cast((rand(*) * 900000000) + 1000000000 as varchar);
You can use last_inserted_id() to then get the most recent number inserted.
If pseudo-random is OK for you, you could create a trigger like this:
create trigger tr_setid before insert on mytable for each row
set new.id := (
select mod ((count(*) ^ 42) * 479001599 + 714320596, 900000000)+100000000
from mytable);
This system is not good if you also delete records from your table, as this solution assumes count(*) is one larger every time this trigger runs.
The multiplier is a prime and not a divisor of 900000000, guaranteeing that no duplicate number will be generated before all possible numbers have been visited.
The ^ operator is just mapping the count(*) so to make the generated series a bit less predictable.
With this trigger the first 10 records in the table will get these id values:
232387754
711389353
174384556
653386155
348394150
827395749
290390952
769392551
900374962
479376561
When I delete a row and create a new one, the primary key doesn't start over at 1, but at 2. I guess that's how it was meant to work when I made it auto_increment. But is it possible to update the primary key whenever a row above it is deleted and all rows under that.
If that isn't possible can I just make another column called rank and make it update depending on what order the rows are in?
There is no reason to care about what the primary keys id is, all that matters is that it's unique. We use sort queries and stuff to worry about order if that's your issue.
If you have code that always requires the primary key to be in the range of 1..number_of_rows with no gaps there is a problem with the design of your application.
You should not make a column called rank, its easy just to do a SELECT * FROM things ORDER BY some_column;
The difference to this is if you need calculated values to sort your table. E.g., an orders total. In order for you to sort orders by their total they need a calculated value on the table. The query is still simple as the one I mentioned.
I use one table withe some casual columns such as id, name, email, etc...also I'm inserting a variable numbers of records in each transaction, to be much efficient I need to have one unique id lets call it transaction id, that would be the same for each group of data which are inserted in one transaction, should be increment. What is the best approach for doing that?
I was thought to use
select max(transaction_id) from users
and increment that value on server side, but that seams like old fashion solution.
You could have another table usergroups with an auto-incrementing primary key, you first insert a record there (maybe including some other useful information about the group). Then get the group's unique id generated during this last insert using mysql_insert_id(), and use that as the groupid for your inserts into the first table.
This way you're still using MySQL's auto-numbering which guarantees you a unique groupid. Doing select max(transaction_id) from users and incrementing this isn't safe, since it's non-atomic (another thread may have read the same max(transaction_id) before you've had a change to increment it, and will start inserting records with a conflicting groupid).
Add new table with auto_increment column
You can create new table with auto_increment column. So you'll be able to generate unique integers in thread safe way. It'll work like this:
DB::insert_into_transaction_table()
transaction_id = DB::mysql_last_insert_id() ## this is integer value
for each record:
DB::insert_into_table(transaction_id, ...other parameters...)
And you don't require mysql transactions for this.
Generate unique string on server side before inserting
You can generate unique id (for example GUID) on server side and use it for all records inserting. But your transaction_id field should be long enough to store values generated this way (some char(...) type). It'll work like this:
transaction_id = new_GUID() ## this is usually a string value
for each record:
DB::insert_into_table(transaction_id, ...other parameters...)