SQL возвращает случайные числа, которых нет в таблице - PullRequest
3 голосов
/ 09 июля 2010

У меня есть таблица с user_ids, которую мы собрали из источника потоковых данных активных учетных записей. Теперь я хочу просмотреть и заполнить информацию о user_ids, которые ничего не делают.

Существует ли SQL-запрос (postgres, если это имеет значение), чтобы запрос возвращал случайные числа, которых нет в таблице?

Например, что-то вроде этого:

SELECT RANDOM(count, lower_bound, upper_bound) as new_id 
WHERE new_id NOT IN (SELECT user_id FROM user_table) AS user_id_table

Возможно, или было бы лучше сгенерировать набор случайных чисел с помощью скриптовой обертки и передать их в БД для определения несуществующих?

Ответы [ 5 ]

2 голосов
/ 10 июля 2010

Это возможно. Если вы хотите, чтобы идентификаторы были целыми числами, попробуйте:

SELECT trunc((random() * (upper_bound - lower_bound)) + lower_bound) AS new_id 
FROM generate_series(1,upper_bound) 
WHERE new_id NOT IN (
    SELECT user_id 
    FROM user_table)
1 голос
/ 27 сентября 2012

Я подозреваю, что вы хотите случайную выборку.Я бы сделал что-то вроде:

SELECT s
  FROM generate_series(1, (select max(user_id) from users) s
  LEFT JOIN users ON s.s = user_id
 WHERE user_id IS NULL
 order by random() limit 5;

Я не проверял это, но идея должна работать.Если у вас много пользователей и не хватает пропущенных идентификаторов, они будут работать лучше, чем другие варианты, но производительность независимо от того, что вы делаете, может быть проблемой.

1 голос
/ 22 июля 2010

Вы можете обернуть запрос выше в подвыбор, то есть

SELECT * FROM (SELECT trunc(random() * (upper - lower) + lower) AS new_id  
FROM generate_series(1, count)) AS x 
WHERE x.new_id NOT IN (SELECT user_id FROM user_table)
0 голосов
/ 30 августа 2018

Мой прагматический подход будет следующим: сгенерировать 500 случайных чисел, а затем выбрать одно, которого нет в таблице:

WITH fivehundredrandoms AS ( RANDOM(count, lower_bound, upper_bound) AS onerandom
FROM (SELECT generate_series(1,500)) AS fivehundred )
SELECT onerandom FROM fivehundredrandoms 
WHERE onerandom NOT IN (SELECT user_id FROM user_table WHERE user_id > 0) LIMIT 1;
0 голосов
/ 21 июня 2018

Есть способ делать то, что вы хотите с рекурсивными запросами, увы, это нехорошо.

Предположим, у вас есть следующая таблица:

CREATE TABLE test (a int)

Для упрощения вы хотите вставить случайные числа от 0 до 4 (random() * 5)::int, которых нет в таблице.

 WITH RECURSIVE rand (i, r, is_new) AS (
  SELECT 
     0,
     null,
     false
  UNION ALL
    SELECT 
      i + 1,
      next_number.v,
      NOT EXISTS (SELECT 1 FROM test WHERE test.a = next_number.v) 
   FROM
     rand r,
     (VALUES ((random() * 5)::int)) next_number(v)
   -- safety check to make sure we do not go into an infinite loop
   WHERE i < 500
)
SELECT * FROM rand WHERE rand.is_new LIMIT 1

Я не уверен, но PostgreSQL должен быть в состоянии прекратить итерации, когда у него будет один результат, так как он знает, что запрос имеет ограничение 1.

Хорошая особенность этого запроса в том, что вы можете заменить (random() * 5)::int на любую функцию генерации идентификатора, которую вы хотите

...