Как создать уникальную случайную строку для одного из столбцов таблицы MySql?
Im, используя MySql 5.5.37. У меня есть таблица со следующими столбцами
+------------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+-------+
| ID | varchar(32) | NO | PRI | NULL | |
| CODE | varchar(6) | NO | UNI | NULL | |
Колонка кода уникальна, а мой идентификатор - GUID. У меня есть ряд строк, которые я бы хотел обновить, с учетом некоторых критериев в приведенной выше таблице (например, WHERE COLUMN1 = 0). Как создать случайные, уникальные 6-символьные коды (идеально буквы и цифры) для моего столбца CODE, чтобы они не нарушали уникальное ограничение в моей таблице? Обратите внимание, что столбцы в таблице, которые не соответствуют критериям (например, где COLUMN1 < > 0) уже имеют уникальные значения для столбца CODE.
Изменить: Это отличается от этого вопроса - Создание случайной и уникальной 8-символьной строки с использованием MySQL, потому что эта ссылка связана с идентификаторами taht являются числовыми. Мои идентификаторы - 32-символьные строки. Также их решение не учитывает тот факт, что в таблице могут быть значения перед запуском операторов, которые я хочу запустить, которые будут генерировать уникальные значения для рассматриваемого столбца.
Ответы
Ответ 1
ДОПОЛНИТЕЛЬНОЕ решение:
Вы можете создать произвольную буквенно-цифровую строку в верхнем регистре с 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 здесь я использую случайную строку из одного символа, чтобы продемонстрировать, что никакое значение не дублируется.
Вы также можете использовать тот же код в триггере 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-значную буквенно-цифровую случайную строку в верхнем регистре. Объедините четыре из них, чтобы получить 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/76933
А как насчет унификации? Хорошо - попытайтесь создать дубликаты; -)
Ответ 2
Это сложно, но я думаю, что достиг хорошего решения:
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
):
-
Получить идентификатор следующей записи, которая будет обновлена
PREPARE stmt FROM "SELECT @id := id, @itemCode := code FROM demo.codes p LIMIT ?, 1;";
EXECUTE stmt USING @i;
-
Получить новый код для записи:
SET @code = getRandomAlphaNumeric();
-
Наконец, проверьте, не существует ли нового кода в таблице, и если в настоящий момент столбец поля не имеет значения (is 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();
Ответ 3
CONV(CONV(( SELECT MAX(CODE) FROM tbl ), 36, 10) + 1, 10, 36)
вы получите следующий "номер", закодированный в базе-36 (цифры и заглавные буквы).
Например:
SELECT CONV(CONV(( 'A1B2C' ), 36, 10) + 1, 10, 36); --> 'A1B2D'
Ответ 4
Попробуйте это для кода
SELECT LEFT(MD5(NOW()), 6) AS CODE;
LEFT(MD5(NOW()), 6)
будет возвращен уникальный код с 6 символами.
Попробуйте другой способ:
SELECT LEFT(UUID(), 6);
LEFT(UUID(), 6)
Это также возвращает уникальный код