#mysql #sql #random
#mysql #sql #Случайный
Вопрос:
У меня есть хранимая процедура, которую я использовал для «деидентификации» информации о клиенте, когда я хочу использовать ее в тестовой среде. Я заменяю фактические имена и адреса случайными значениями. У меня есть таблицы базы данных в базе данных с именем dict (для словаря) для женских имен, мужских имен, фамилий и адресов.
У каждого из них есть поле с именем f_row_id, которое представляет собой последовательный номер от 1 до x, по одному для каждой записи в таблице.
Недавно мы обновились до MySQL 8, и хранимая процедура перестала работать. В итоге я получил значение NULL для каждого поля, в котором я пытался заполнить случайное значение из другой таблицы. Пытаясь найти то, что теперь будет работать, я не могу заставить следующий запрос работать так, как я ожидаю:
SELECT
f_enroll_id,
(SELECT f_name FROM dict.dummy_female_first_name fn WHERE fn.f_row_id = (FLOOR(RAND() * 850) 1) LIMIT 1)
FROM
t_enroll
Моя таблица данных (которую я в конечном итоге хочу содержать со случайными именами) называется t_enroll . В этом есть поле ID (f_enroll_id) Я хочу получить список каждого идентификатора и случайное имя для каждой записи в этой таблице.
В таблице случайных имен (dummy_female_first_name) 850 записей (в моей хранимой процедуре это переменная сеанса, которую я вычисляю в начале процедуры).
Когда я впервые попытался запустить это, я получил сообщение об ошибке, что мой подзапрос вернул более одного значения. Я не понимаю, зачем это делать, поскольку (FLOOR(RAND() * 850) 1) должен возвращать одно целое число. Поэтому я добавил ОГРАНИЧЕНИЕ 1. Но когда я запускаю это, около половины возвращаемых строк имеют значение NULL для первого имени.
Я проверил, что все строки в моей таблице имен имеют идентификатор строки, что идентификатор строки уникален, и в числах нет пробелов.
Как вы думаете, что является причиной этого?
Заранее спасибо!
Вот схема для таблицы, которую я обновляю:
CREATE TABLE `t_enroll` (
`f_enroll_id` int(15) NOT NULL AUTO_INCREMENT,
`f_status` int(2) DEFAULT NULL,
`f_date_enrolled` date NOT NULL DEFAULT '0000-00-00',
`f_first_name` varchar(20) DEFAULT NULL,
`f_mi` char(1) DEFAULT NULL,
`f_last_name` varchar(20) NOT NULL DEFAULT '',
`f_maiden_name` varchar(20) DEFAULT NULL,
`f_dob` date NOT NULL DEFAULT '0000-00-00',
`f_date_fee_received` date NOT NULL DEFAULT '0000-00-00',
`f_gender` int(11) NOT NULL DEFAULT '2',
`f_address_1` varchar(40) DEFAULT NULL,
`f_address_2` varchar(20) DEFAULT NULL,
`f_quadrant` char(2) DEFAULT NULL,
`f_city` varchar(25) DEFAULT NULL,
`f_state` char(2) NOT NULL DEFAULT '',
`f_county` varchar(3) NOT NULL,
`f_zip_code` varchar(10) DEFAULT NULL,
PRIMARY KEY (`f_enroll_id`),
KEY `f_date_enrolled` (`f_date_enrolled`),
KEY `f_last_name` (`f_last_name`),
KEY `f_first_name` (`f_first_name`),
KEY `f_dob` (`f_dob`),
KEY `f_gender` (`f_gender`)
ENGINE=InnoDB AUTO_INCREMENT=532 DEFAULT CHARSET=latin1 COMMENT='InnoDB free: 15360 kB';
Вот схема для таблицы словаря, из которой я извлекаю имена:
CREATE TABLE `dummy_female_first_name` (
`f_row_id` int(11) NOT NULL,
`f_name` varchar(25) NOT NULL,
PRIMARY KEY (`f_row_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Как я упоминал в своем комментарии, я нашел альтернативный подход, используя вариант ORDER BY RAND() LIMIT 1 . Но мне все еще любопытно, что происходит, из-за чего мой оригинальный метод не сработал. Это то, что изменилось в более поздней версии MySQL, потому что раньше это работало.
Еще раз спасибо.
Комментарии:
1. пожалуйста, покажите вашу схему (вывод
show create table dict.dummy_female_first_name
иshow create table t_enroll
) и образец данных, которые воспроизводят проблему2. Очевидно, я все еще изучаю публикацию здесь, потому что я не уверен, как предоставить мою схему. Когда я пытаюсь добавить его в качестве комментария, он говорит, что мой комментарий слишком длинный. Должен ли я публиковать схему в нескольких небольших комментариях?
3. Кстати, я нашел способ обойти это. Если я изменю: (ВЫБЕРИТЕ f_name ИЗ dict.dummy_female_first_name fn, ГДЕ fn.f_row_id = (FLOOR(RAND() * 850) 1) LIMIT 1) на (ВЫБЕРИТЕ f_name ИЗ dict.dummy_female_first_name fn ПОРЯДОК ПО RAND() LIMIT 1) это работает.
4. нет, просто отредактируйте свой вопрос и добавьте его. комментарии не очень полезны для кода или sql
Ответ №1:
Это гораздо более дорогостоящий подход, но вы можете использовать:
SELECT f_enroll_id,
(SELECT f_name FROM dict.dummy_female_first_name fn ORDER BY rand() LIMIT 1)
FROM t_enroll;
Вы можете сделать это более эффективным, используя:
SELECT f_enroll_id,
(SELECT f_name
FROM dict.dummy_female_first_name fn
WHERE rand() < 0.01
ORDER BY rand() LIMIT 1
)
FROM t_enroll;
where
Предложение означает, что будет отфильтровано около 8 строк, поэтому сортировка будет намного быстрее.