I am generating new ids for my animals and i am running the following Query
SELECT concat('TZ',YEAR(CURDATE()),FLOOR(RAND() * 999999.99)) as ID , animalid FROM adggeth.view_allanimals;
my output for the following query is
# ID, animalid
'TZ2019703169', 'TZN000044001722'
'TZ2019914906', 'TZN000067976797'
'TZ2019465022', 'TZN000094299429'
'TZ2019580395', 'TZN000192792688'
my expected output
# ID, animalid
'TZ2019000001', 'TZN000044001722'
'TZ2019000002', 'TZN000067976797'
'TZ2019000003', 'TZN000094299429'
'TZ2019000004', 'TZN000192792688'
How can generate a random number for my id to achieve the expected output
After changes i get the following unexpected error
using
CONCAT('TZ', YEAR(CURDATE()), LPAD(#seq, 6, '0'))
'TZ2019000001', 'TZN000044001722'
'TZ2019000001', 'TZN000067976797'
'TZ2019000001', 'TZN000094299429'
'TZ2019000001', 'TZN000192792688'
It looks like you want IDs with the format TZYYYYNNNNNN where YYYY is the present year and NNNNNN is a guaranteed sequential number. Here you ask about how to generate the sequential number in a way where it's guaranteed to be unique.
If you were using Oracle you could use a sequence object. But who can afford Oracle?
So, you need to simulate the sequence object in MySQL. It's a little nasty, but here we go:
Create the following table:
CREATE TABLE sequence (
sequence_id BIGINT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`sequence_id`)
)
Then, each time you need a new sequence number, issue these three queries one after the other:
INSERT INTO sequence () VALUES ();
DELETE FROM sequence WHERE sequence_id < LAST_INSERT_ID();
SET #seq := LAST_INSERT_ID();
The third line places a guaranteed unique number into the #seq variable. This guarantee holds even if you have dozens of different client programs connected to your database generating sequence numbers. (The DELETE query merely keeps this otherwise pointless table from taking up too much space.)
Once you have #seq you can use it to generate your id values, something like this.
CONCAT('TZ', YEAR(CURDATE()), LPAD(#seq, 6, '0'))
To reset the sequence number at the first of the next year simply drop and recreate the sequence table.
Related
I have table of Users in MariaDB and I need to generate serviceNumber for each newly created user.
Example of this code: 865165
Only two requirements are:
Unique in User table
Unpredictable when creating user (Not based on AutoIncrement maybe?)
Is this possible with just database? Or I need to implement it in backend when creating user.
The only (theoretically) collision free solution would be to generate the serviceNumber with UUID() function (or maybe UUID_SHORT()).
The disadvantage of this solution is, that it can't be used in statement based replication, in this case you should create the value in your backend.
Steps 1-3 are setup steps:
Decide on how big you want the numbers to be. 6-digit numbers would let you have a million numbers.
Build a temp table t with all 6-digit numbers (t_num).
Build and populate a permanent table:
CREATE TABLE `u` (
id INT AUTO_INCREMENT NOT NULL,
t_num INT NOT NULL,
PRIMARY KEY(id)
);
INSERT INTO u (t_num)
SELECT t_num FROM t ORDER BY RAND();
4--Plan A You have an auto_inc id in the real table; simply join to u to get the random 6-digit number.
4--Plan B
BEGIN;
SELECT t_num FROM u ORDER BY id LIMIT 1 FOR UPDATE; -- to get the random id
DELETE FROM u ORDER BY id LIMIT 1; -- Remove it from the list of available ids
From MySQL reference manual:
To obtain a random integer R in the range i <= R < j, use the
expression FLOOR(i + RAND() * (j − i)). For example, to obtain a
random integer in the range the range 7 <= R < 12, use the following
statement: SELECT FLOOR(7 + (RAND() * 5));
Make the field holding serviceNumber uniqe and use the above math expression to generate serviceNumbers.
I have a table containing:
Order Nr (Number)
Product (Short text)
Material (Short text)
Date (Date)
Amount (Number)
From (Number)
To (Number)
[From] and [To] repeat themselves with each [Order Nr]
How can I create in MS Access a new column containing a sequence using as boundaries values from columns [From] and [To]? (I tried concat, but it returns short text).
On top of that I would like to duplicate all of the values from other columns and paste them to the newly created rows accordingly. (That I guess would be a self-join, but I'm not sure how to proceed)
Values From and To which are my sequence boundaries have no pattern (meaning I never know how many [Products] will be in an [Order] and how will it be distributed).
into
You can join in a sequence table to get the desired results.
Personally, I use a sequence generating query based on MSysObjects, but others advocate just having a table with numbers.
First, create the sequence table/query, mine is named qSequence:
SELECT DISTINCT Abs(ones.ID Mod 10)+(Abs(tens.ID Mod 10)*10)+1 AS Sequence
FROM MSysObjects AS ones, MSysObjects AS tens;
This just generates a sequence of 1 to 100, I assume that meets your needs.
Then, we can just join in the sequence table:
SELECT MyTable.*, qSequence.Sequence
FROM MyTable, qSequence
WHERE qSequence.Sequence BETWEEN MyTable.From AND MyTable.To
I had a table with 3 columns and 3600K rows. Using MySQL as a key-value store.
The first column id was VARCHAR(8) and set to primary key.The 2nd and 3rd columns were MEDIUMTEXT. When calling SELECT * FROM table WHERE id=00000 MySQL took like 54 sec ~ 3 minutes.
For testing I created a table containing VARCHAR(8)-VARCHAR(5)-VARCHAR(5) where data casually generated from numpy.random.randint. SELECT takes 3 sec without primary key. Same random data with VARCHAR(8)-MEDIUMTEXT-MEDIUMTEXT, the time cost by SELECT was 15 sec without primary key.(note: in second test, 2nd and 3rd column actually contained very short text like '65535', but created as MEDIUMTEXT)
My question is: how can I achieve similar performance on my real data? (or, is it impossible?)
If you use
SELECT * FROM `table` WHERE id=00000
instead of
SELECT * FROM `table` WHERE id='00000'
you are looking for all strings that are equal to an integer 0, so MySQL will have to check all rows, because '0', '0000' and even ' 0' will all be casted to integer 0. So your primary key on id will not help and you will end up with a slow full table. Even if you don't store values that way, MySQL doesn't know that.
The best option is, as all comments and answers pointed out, to change the datatype to int:
alter table `table` modify id int;
This will only work if your ids casted as integer are unique (so you don't have e.g. '0' and '00' in your table).
If you have any foreign keys that references id, you have to drop them first and, before recreating them, change the datatype in the other columns too.
If you have a known format you are storing your values (e.g. no zeros, or filled with 0s up to the length of 8), the second best option is to use this exact format to do your query, and include the ' to not cast it to integer. If you e.g. always fill 0 to 8 digits, use
SELECT * FROM `table` WHERE id='00000000';
If you never add any zeros, still add the ':
SELECT * FROM `table` WHERE id='0';
With both options, MySQL can use your primary key and you will get your result in milliseconds.
If your id column contains only numbers so define it as int , because int will give you better performance ( it is more faster)
Make the column in your table (the one defined as key) integer and retry. Check first performance by running a test within your DB (workbench or simple command line). You should get a better result.
Then, and only if needed (I doubt it though), modify your python to convert from integer to string (and/or vise-versa) when referencing the key column.
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
I have a view over three tables. It has 6 columns as follows:
ID | NAME | PRINCIPAL_ID | DESCRIPTION | GROUP_ID | TYPE
As I'm using hibernate to retrieve data from database, I had to put the ID column in this view. The problem is, I cannot generate a unique ID which seems to be necessary for hibernate to correctly load the data.
How can I have a unique ID for every row in this view?
Maybe this can help, I'm not sure: The combination of PRINCIPAL_ID and GROUP_ID can make a unique ID. All these three are Long.
UPDATE: When you insist to have it as a number, create your view like this:
SELECT
(#rownum:=#rownum + 1) AS rownumber,
yourTable.*
FROM
yourTable
, (SELECT #rownum:=0) r
But that's really it - no more other possibilities. Cast rownumber as long like I said in comments, if it really, really has to be long.
Alternatively in a procedure:
DELIMITER $$
CREATE PROCEDURE selectFromWhatever()
BEGIN
SELECT
(#rownum:=#rownum + 1) AS rownumber,
yourTable.*
FROM
yourTable
, (SELECT #rownum:=0) r;
END $$
DELIMITER ;
Then get result with
CALL selectFromWhatever()
Original answer:
From the MySQL manual:
UUID()
Returns a Universal Unique Identifier (UUID) generated according to
“DCE 1.1: Remote Procedure Call” (Appendix A) CAE (Common Applications
Environment) Specifications published by The Open Group in October
1997 (Document Number C706,
http://www.opengroup.org/public/pubs/catalog/c706.htm).
A UUID is designed as a number that is globally unique in space and
time. Two calls to UUID() are expected to generate two different
values, even if these calls are performed on two separate computers
that are not connected to each other.
A UUID is a 128-bit number represented by a utf8 string of five
hexadecimal numbers in aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee format:
The first three numbers are generated from a timestamp.
The fourth number preserves temporal uniqueness in case the timestamp value loses monotonicity (for example, due to daylight
saving time).
The fifth number is an IEEE 802 node number that provides spatial uniqueness. A random number is substituted if the latter is not
available (for example, because the host computer has no Ethernet
card, or we do not know how to find the hardware address of an
interface on your operating system). In this case, spatial uniqueness
cannot be guaranteed. Nevertheless, a collision should have very low
probability.
Currently, the MAC address of an interface is taken into account only on FreeBSD and Linux. On other operating systems, MySQL uses a
randomly generated 48-bit number.
mysql> SELECT UUID();
-> '6ccd780c-baba-1026-9564-0040f4311e29'
Warning
Although UUID() values are intended to be unique, they are not
necessarily unguessable or unpredictable. If unpredictability is
required, UUID values should be generated some other way. Note
UUID() does not work with statement-based replication.
Another way would be to use CONCAT() to build your unique ID.
SELECT CONCAT(PRINCIPAL_ID, '-', GROUP_ID) AS myUniqueID
FROM yourTable
Alternative is use ROW_NUMBER() OVER ()
SELECT ROW_NUMBER() OVER () AS ROW_NUM ... COLUMN... FROM TABLE