2013-07-31 2 views
0

Пусть у меня есть таблица:SQL случайное число, которое не повторяется в группе

HH SLOT RN 
-------------- 
1  1 null 
1  2 null 
1  3 null 
-------------- 
2  1 null 
2  2 null 
2  3 null 

Я хочу, чтобы установить RN быть случайное число в диапазоне от 1 до 10. Это нормально для числа повторить через весь стол, но это bad, чтобы повторить номер в пределах любой данной HH. Например,:

HH SLOT RN_GOOD RN_BAD 
-------------------------- 
1  1  9  3 
1  2  4  8 
1  3  7  3 <--!!! 
-------------------------- 
2  1  2  1 
2  2  4  6 
2  3  9  4 

Это на Netezza, если это имеет значение. Это для меня настоящий помощник. Заранее спасибо!

+0

Почему бы не добавить уникальный индекс на '(HH, RN)' и повторить попытку в случае неудачи? –

+0

Netezza не применяет уникальный индекс. Я не знаю, является ли это просто нашей конфигурацией или если это вся система. – Chris

+0

Я стою исправленный! –

ответ

0

Ну, я не мог получить пятно решения, так что я сделал хак:

  1. Создан новое целое поле, называемое rand_inst.
  2. Назначьте случайное число для каждого пустого слота.
  3. Обновление rand_inst будет номером экземпляра этого случайного числа в этом доме. Например, если я получу два 3, то второй 3 будет иметь rand_inst, установленный в 2.
  4. Обновить таблицу, чтобы назначить различное случайное число в любом месте rand_inst>1.
  5. Повторите назначение и обновление, пока мы не сходимся на решении.

Вот как он выглядит. Лень anonymise, поэтому имена немного отличается от моей должности:

/* Iterative hack to fill 6 slots with a random number between 1 and 13. 
    A random number *must not* repeat within a household_id. 
*/ 
update c3_lalfinal a 
set a.rand_inst = b.rnum 
from (
    select household_id 
      ,slot_nbr 
      ,row_number() over (partition by household_id,rnd order by null) as rnum 
    from c3_lalfinal 
) b 
where a.household_id = b.household_id 
    and a.slot_nbr = b.slot_nbr 
; 

update c3_lalfinal 
set rnd = CAST(0.5 + random() * (13-1+1) as INT) 
where rand_inst>1 
; 

/* Repeat until this query returns 0: */ 
select count(*) from (
    select household_id from c3_lalfinal group by 1 having count(distinct(rnd)) <> 6 
) x 
; 
0

Я не эксперт по SQL, но, вероятно, сделать что-то вроде этого:

  1. Инициализировать счетчик CNT = 1
  2. Создать таблицу такое, что вы образец 1 строку случайным образом из каждой группы и подсчета нулевого RN, скажем C_NULL_RN.
  3. С вероятностью C_NULL_RN/(10-CNT + 1) для каждой строки, назначить CNT, как RN
  4. Приращение CNT и перейти к шагу 2
+0

Возможно, в сохраненной программе я мог бы снять это.На самом деле, вы заставили меня задуматься о том, может ли он работать в автономном режиме с помощью python, если я могу сделать работу sql. – Chris

+1

@Chris Или вы можете написать программу python, которая подключается к SQL-серверу и запускает сфабрикованные запросы. – ElKamina

1

Чтобы получить случайное число между 1 и число строк в hh, вы можете использовать:

select hh, slot, row_number() over (partition by hh order by random()) as rn 
from t; 

Более широкий диапазон значений является более сложным. Следующее вычисляет таблицу (называемую randoms) с числами и случайным положением в том же диапазоне. Затем он использует slot индексировать в положение и вытяните случайное число из randoms таблицы:

with nums as (
     select 1 as n union all select 2 union all select 3 union all select 4 union all select 5 union all 
     select 6 union all select 7 union all select 8 union all select 9 
    ), 
    randoms as (
     select n, row_number() over (order by random()) as pos 
     from nums 
    ) 
select t.hh, t.slot, hnum.n 
from (select hh, randoms.n, randoms.pos 
     from (select distinct hh 
      from t 
      ) t cross join 
      randoms 
    ) hnum join 
    t 
    on t.hh = hnum.hh and 
     t.slot = hnum.pos; 

Here является SQLFiddle, который демонстрирует это в Postgres, который я предполагаю, достаточно Netezza близко, чтобы иметь соответствующий синтаксис.