How to generate unique id in MySQL?

前端 未结 16 2618
生来不讨喜
生来不讨喜 2020-11-29 03:17

I\'m programming a script using PHP and MySQL and I want to get a unique id (consisting of a string: capitals and small letters with numbers) like: gHYtUUi5b.

相关标签:
16条回答
  • 2020-11-29 03:49

    This generates random ids:

    CREATE TABLE Persons (
        ID Integer PRIMARY KEY AUTOINCREMENT,
        LastName varchar(255) NOT NULL,
        FirstName varchar(255),
        Age int
    );
    
    0 讨论(0)
  • 2020-11-29 03:49

    You could use Twitter's snowflake.

    In short, it generates a unique id based on time, server id and a sequence. It generates a 64-bit value so it is pretty small and it fits in an INT64. It also allows for sorting values correctly.

    https://developer.twitter.com/en/docs/basics/twitter-ids

    In sum, it allows multiple servers, highly concurrency, sorting value and all of them in 64 bits.

    Here it is the implementation for MySQL

    https://github.com/EFTEC/snowflake-mysql

    It consists of a function and a table.

    0 讨论(0)
  • 2020-11-29 03:52

    How you generate the unique_ids is a useful question - but you seem to be making a counter productive assumption about when you generate them!

    My point is that you do not need to generate these unique id's at the time of creating your rows, because they are essentially independent of the data being inserted.

    What I do is pre-generate unique id's for future use, that way I can take my own sweet time and absolutely guarantee they are unique, and there's no processing to be done at the time of the insert.

    For example I have an orders table with order_id in it. This id is generated on the fly when the user enters the order, incrementally 1,2,3 etc forever. The user does not need to see this internal id.

    Then I have another table - unique_ids with (order_id, unique_id). I have a routine that runs every night which pre-loads this table with enough unique_id rows to more than cover the orders that might be inserted in the next 24 hours. (If I ever get 10000 orders in one day I'll have a problem - but that would be a good problem to have!)

    This approach guarantees uniqueness and takes any processing load away from the insert transaction and into the batch routine, where it does not affect the user.

    0 讨论(0)
  • 2020-11-29 03:53

    To get unique and random looking tokens you could just encrypt your primary key i.e.:

    SELECT HEX(AES_ENCRYPT(your_pk,'your_password')) AS 'token' FROM your_table;

    This is good enough plus its reversable so you'd not have to store that token in your table but to generate it instead.

    Another advantage is once you decode your PK from that token you do not have to do heavy full text searches over your table but simple and quick PK search.

    Theres one small problem though. MySql supports different block encryption modes which if changed will completely change your token space making old tokens useless...

    To overcome this one could set that variable before token generated i.e.:

    SET block_encryption_mode = 'aes-256-cbc';

    However that a bit waste... The solution for this is to attach an encryption mode used marker to the token:

    SELECT CONCAT(CONV(CRC32(@@GLOBAL.block_encryption_mode),10,35),'Z',HEX(AES_ENCRYPT(your_pk,'your_password'))) AS 'token' FROM your_table;
    

    Another problem may come up if you wish to persist that token in your table on INSERT because to generate it you need to know primary_key for the record which was not inserted yet... Ofcourse you might just INSERT and then UPDATE with LAST_INSERT_ID() but again - theres a better solution:

    INSERT INTO your_table ( token )
    SELECT CONCAT(CONV(CRC32(@@GLOBAL.block_encryption_mode),10,35),'Z',HEX(AES_ENCRYPT(your_pk,'your_password'))) AS 'token'
    FROM information_schema.TABLES 
    WHERE  TABLE_SCHEMA = DATABASE() AND TABLE_NAME = "your_table";
    

    One last but not least advantage of this solution is you can easily replicate it in php, python, js or any other language you might use.

    0 讨论(0)
  • 2020-11-29 03:57

    A programmatic way can be to:

    • add a UNIQUE INDEX to the field
    • generate a random string in PHP
    • loop in PHP ( while( ! DO_THE_INSERT ) )
      • generate another string

    Note:

    • This can be dirty, but has the advantage to be DBMS-agnostic
    • Even if you choose to use a DBMS specific unique ID generator function (UUID, etc) it is a best practice to assure the field HAS to be UNIQUE, using the index
    • the loop is statistically not executed at all, it is entered only on insert failure
    0 讨论(0)
  • 2020-11-29 03:58
    DELIMITER $$
    
    USE `temp` $$
    
    DROP PROCEDURE IF EXISTS `GenerateUniqueValue`$$
    
    CREATE PROCEDURE `GenerateUniqueValue`(IN tableName VARCHAR(255),IN columnName VARCHAR(255)) 
    BEGIN
        DECLARE uniqueValue VARCHAR(8) DEFAULT "";
        DECLARE newUniqueValue VARCHAR(8) DEFAULT "";
        WHILE LENGTH(uniqueValue) = 0 DO
            SELECT CONCAT(SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                    SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                    SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                    SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                    SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                    SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                    SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                    SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1)
                    ) INTO @newUniqueValue;
            SET @rcount = -1;
            SET @query=CONCAT('SELECT COUNT(*) INTO @rcount FROM  ',tableName,' WHERE ',columnName,'  like ''',newUniqueValue,'''');
            PREPARE stmt FROM  @query;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;
        IF @rcount = 0 THEN
                SET uniqueValue = @newUniqueValue ;
            END IF ;
        END WHILE ;
        SELECT uniqueValue;
        END$$
    
    DELIMITER ;
    

    And call the stored procedure as GenerateUniqueValue('tableName','columnName'). This will give you a 8 digit unique character everytime.

    0 讨论(0)
提交回复
热议问题