web-dev-qa-db-ja.com

MySqlテーブル列の1つに対して一意のランダムな文字列を生成するにはどうすればよいですか?

MySql 5.5.37を使用しています。次の列を持つテーブルがあります

+------------------+------------------+------+-----+---------+-------+
| Field            | Type             | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+-------+
| ID               | varchar(32)      | NO   | PRI | NULL    |       |
| CODE             | varchar(6)       | NO   | UNI | NULL    |       |

コード列は一意であり、ID列はGUIDです。上記の表のいくつかの基準(WHERE COLUMN1 = 0など)に従って、更新したい行がいくつかあります。 CODE列のランダムな一意の6文字コード(理想的には文字と数字)を生成して、テーブルの一意制約に違反しないようにするにはどうすればよいですか?条件を満たさないテーブルの列(例:COLUMN1 <> 0)には、既にCODE列の一意の値があります。

編集: これはこの質問とは異なります- MySQL を使用してランダムで一意の8文字の文字列を生成するのは、そのリンクがIDを処理するためです。私のIDは32文字の文字列です。また、それらのソリューションは、実行したいステートメントを実行する前にテーブルに値があり、問題の列に一意の値を生成するという事実を考慮していません。

17
Dave

更新前のトリガーソリューション:

以下を使用して、6文字のランダムな英数字の大文字ストリングを作成できます。

lpad(conv(floor(Rand()*pow(36,6)), 10, 36), 6, 0);

既存の文字列を作成しないために、BEFORE UPDATEトリガーを使用できます。

DELIMITER //
CREATE TRIGGER `unique_codes_before_update`
BEFORE UPDATE ON `unique_codes` FOR EACH ROW 
BEGIN
    declare ready int default 0;
    declare rnd_str text;
    if new.CODE is null then
        while not ready do
            set rnd_str := lpad(conv(floor(Rand()*pow(36,6)), 10, 36), 6, 0);
            if not exists (select * from unique_codes where CODE = rnd_str) then
                set new.CODE = rnd_str;
                set ready := 1;
            end if;
        end while;
    end if;
END//
DELIMITER ;

CODEステートメントでNULL列をUPDATEに設定するたびに、トリガーはテーブル内で一致が見つからなくなるまでループ内に新しいランダム文字列を作成します。

これで、すべてのNULL値を次のものに置き換えることができます。

update unique_codes set CODE = NULL where code is NULL;

SQLFiddle demo here iでは、1文字のランダムな文字列を使用して、値が重複していないことを示します。

BEFORE INSERTトリガーで同じコードを使用することもできます。この方法では、CODE=NULLを使用して新しい行を挿入するだけで、トリガーはそれを新しい一意のランダムな文字列に設定します。また、再度更新する必要はありません。

元の回答(32文字の文字列):

select lpad(conv(floor(Rand()*pow(36,8)), 10, 36), 8, 0) as rnd_str_8;

-- output example: 3AHX44TF

8文字の英数字の大文字のランダム文字列を生成します。 4つを連結して32文字を取得します。

select concat(
    lpad(conv(floor(Rand()*pow(36,8)), 10, 36), 8, 0),
    lpad(conv(floor(Rand()*pow(36,8)), 10, 36), 8, 0),
    lpad(conv(floor(Rand()*pow(36,8)), 10, 36), 8, 0),
    lpad(conv(floor(Rand()*pow(36,8)), 10, 36), 8, 0)
) as rnd_str_32;

-- output example: KGC8A8EGKE7E4MGD4M09U9YWXVF6VDDS

http://sqlfiddle.com/#!9/9eecb7d/769

では、均一性はどうでしょうか?まあ-複製を生成してみてください;-)

19
Paul Spiegel
CONV(CONV(( SELECT MAX(CODE) FROM tbl ), 36, 10) + 1, 10, 36)

base-36(数字と大文字)でエンコードされた次の「番号」を取得します。

例えば:

SELECT CONV(CONV(( 'A1B2C' ), 36, 10) + 1, 10, 36); --> 'A1B2D'
1
Rick James
DELIMITER $$

USE `db` $$

DROP PROCEDURE IF EXISTS `GenerateUniqueValue`$$

CREATE PROCEDURE `GenerateUniqueValue`(IN tableName VARCHAR(255),IN columnName VARCHAR(255)) 
BEGIN
    DECLARE uniqueValue 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 ;

このストアドプロシージャを次のように呼び出します

Call GenerateUniqueValue('tableName','columnName')

これにより、一意の8文字の文字列が毎回提供されます。

これはトリッキーですが、ニースのソリューションに到達したと思います。

_DROP FUNCTION IF EXISTS getRandomAlphaNumeric;

DELIMITER $$

CREATE FUNCTION getRandomAlphaNumeric() RETURNS CHAR(6)
DETERMINISTIC
BEGIN

    SELECT 
    CONCAT (
        CHAR(FLOOR(Rand()*10)+48), CHAR(FLOOR(Rand()*26)+65), CHAR(FLOOR(Rand()*26)+97),
        CHAR(FLOOR(Rand()*10)+48), CHAR(FLOOR(Rand()*26)+65), CHAR(FLOOR(Rand()*26)+97)
    ) INTO @code
    ;

    RETURN @code;
END
$$

DELIMITER ;


DROP PROCEDURE IF EXISTS generateCodes;

DELIMITER $$
CREATE PROCEDURE generateCodes()
BEGIN

    SET @count = 0;
    SELECT COUNT(1) INTO @count FROM demo.codes;

    SET @i = 0;
    WHILE @i < @count DO

        PREPARE stmt FROM "SELECT @id := id, @itemCode := code FROM demo.codes p LIMIT ?, 1;";
        EXECUTE stmt USING @i;

        SET @code = getRandomAlphaNumeric();

        SELECT COUNT(1) INTO @countRowsWithCode FROM demo.codes WHERE code = @code;

        IF @countRowsWithCode = 0 AND @itemCode IS NULL THEN
            UPDATE demo.codes SET code = @code WHERE id = @id;
        END IF;

        SET @i := @i + 1;   
    END WHILE;
END
$$

DELIMITER ;


CALL generateCodes();
_

まず、目的のコードを生成するために使用される6文字のランダムな文字列を返す関数を作成しました。

_DROP FUNCTION IF EXISTS getRandomAlphaNumeric;

DELIMITER $$

CREATE FUNCTION getRandomAlphaNumeric() RETURNS CHAR(6)
DETERMINISTIC
BEGIN

    SELECT 
    CONCAT (
        CHAR(FLOOR(Rand()*10)+48), CHAR(FLOOR(Rand()*26)+65), CHAR(FLOOR(Rand()*26)+97),
        CHAR(FLOOR(Rand()*10)+48), CHAR(FLOOR(Rand()*26)+65), CHAR(FLOOR(Rand()*26)+97)
    ) INTO @code
    ;

    RETURN @code;
END
$$
_

次に、ランダムな一意のコードでテーブルを更新する手順を作成しました。手順は次のとおりです。

  • 6文字の新しいランダムなコードで更新されるすべてのレコードをカウントします。

    SELECT COUNT(1) INTO @count FROM demo.codes;

  • 次に、foreach行(WHILEループを使用):

    • 更新する次のレコードのIDを取得します

      _PREPARE stmt FROM "SELECT @id := id, @itemCode := code FROM demo.codes p LIMIT ?, 1;";_ _EXECUTE stmt USING @i;_

    • レコードの新しいコードを取得します。

      SET @code = getRandomAlphaNumeric();

    • 最後に、新しいコードがテーブルにまだ存在していないか確認し、現在フィールド列に値がない(NULL、ない場合、現在のレコードを更新しますランダムコード:

      SELECT COUNT(1) INTO @countRowsWithCode FROM demo.codes WHERE code = @code; IF @countRowsWithCode = 0 AND @itemCode IS NULL THEN UPDATE demo.codes SET code = @code WHERE id = @id; END IF;

    • 最後に、CALLであるPROCEDURE列からフィールドにデータを入力するために、codeが作成されたNULLになります。

      CALL generateCodes();

0

コードでこれを試してください

_SELECT LEFT(MD5(NOW()), 6) AS CODE;
_

LEFT(MD5(NOW()), 6)これは、6文字の一意のコードを返します。

このような別の方法を試してください

_SELECT LEFT(UUID(), 6);
_

LEFT(UUID(), 6)これは一意のコードも返します

0
krunal nerikar