Встановити випадкове значення з набору


11

Мені потрібно помістити деякі випадкові значення в базу даних, але я не хочу закінчувати повністю рандомізованим текстом (наприклад, 7hfg43d3). Натомість я хотів би випадковим чином вибрати одне із значень, наданих самим собою.

Відповіді:


26

Хороша ідея. Пропоную два незначні спрощення:

('{Foo,Bar,Poo}'::text[])[ceil(random()*3)]
  • Простіший синтаксис з використанням літералу масиву ( '{Foo,Bar,Poo}'::text[]) Скорочує рядок для більш довгих списків. Додаткова вигода: явна декларація типу працює для будь-якого типу, а не лише для text. Ваша оригінальна ідея трапляється для виведення text, тому що це тип за замовчуванням для рядкових літералів.

  • Використовуйте ceil()замість floor() + 1. Той самий результат.

Добре, теоретично нижня межа може бути 0 точно, як натякає у вашому коментарі , оскільки random()виробляє ( цитуючи тут посібник ):

випадкове значення в діапазоні 0,0 <= x <1,0

Однак я ніколи не бачив, щоб це сталося. Виконайте пару мільйонів тестів:

SELECT count(*)
FROM   generate_series(1,1000000)
WHERE  ceil(random())::int = 0;

-> SQLfiddle

Щоб бути абсолютно безпечним, ви можете використовувати підписи на власні масиви Postgres і все ж уникати додаткових доповнень:

('[0:2]={Foo,Bar,Poo}'::text[])[floor(random()*3)]

Деталі під цим пов’язаним запитанням про SO.

Або ще краще, використовуйте trunc(), це трохи швидше.

('[0:2]={Foo,Bar,Poo}'::text[])[trunc(random()*3)]

стеля (0) == підлога (0) + 1?
Корда

@korda: Я додав ще, вирішуючи це.
Ервін Брандстеттер

@ErwinBrandstetter Ви не думаєте, що ceil(random())::intзавжди дасть вам 1, так що ви не зможете перевірити, чи коли-небудь поверне 0?
aki92

@ aki92: ceil(0.0)ні, не в цьому справа. Ото: для цілей цього тесту ми могли б спростити: WHERE random() = 0.0.
Ервін Брандстетер

@ErwinBrandstetter О правда, вибачте, що просто пропустив цю річ.
aki92

8

Я придумав ідею використовувати масиви для цього:

(ARRAY['Foo','Bar','Poo'])[floor(random()*3)+1]

0

На основі цієї ідеї я створив функцію, яка була мені дуже корисною:

CREATE OR REPLACE FUNCTION random_choice(
    choices text[]
)
RETURNS text AS $$
DECLARE
    size_ int;
BEGIN
    size_ = array_length(choices, 1);
    RETURN (choices)[floor(random()*size_)+1];
END
$$ LANGUAGE plpgsql;

Приклади використання:

  • SELECT random_choice(array['h', 'i', 'j', 'k', 'l']) as random_char;

  • SELECT random_choice((SELECT array_agg(name) FROM pets)) AS pet_name;


Ви можете перетворити цю функцію у функцію з варіативним параметром, який я особисто вважаю зручнішим для користувачів.
Сахап Асці
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.