Выбрать ТОП 1 из записей с учетом веса

Я уже видел этот пост здесь (http://stackoverflow.com/questions/1398113/sql-select-one-row-randomly-but-taking-into-account-a-weight), но не смог с этим справиться. Куда мне поместить таблицу «Материал»? Почему они не используют NEWID () вместо RND ()?

Столовая Вещь

id     item       weight       location
1      ball       1            Wyoming
2      cup        2            Alaska
3      sock       1            Idaho
4      car        3            Miami
5      hot girl   5            Brazil

Теперь, согласно упомянутой выше статье, я должен сделать это

SELECT      TOP 1 t.*
FROM        @Table t
INNER JOIN (SELECT t.id, sum(tt.weight) AS cum_weight
            FROM        @Table t
            INNER JOIN  @Table tt ON  tt.id <= t.id
            GROUP BY    t.id) tc
        ON  tc.id = t.id,
           (SELECT  SUM(weight) AS total_weight FROM @Table) tt,
           (SELECT  RAND() AS rnd) r
WHERE       r.rnd * tt.total_weight <= tc.cum_weight
ORDER BY    t.id ASC

Я хочу сделать то же самое, но следующим образом:

SELECT TOP (1) from stuff WHERE blahblahblah AND (location='Brazil' OR location='Wyoming' OR location='Brazil') AND (weight <= cum_weight) ORDER BY NEWID()

Я только предполагаю, что могу использовать NEWID () и не буду вынужден использовать RND ()


person Patriotec    schedule 20.05.2012    source источник
comment
Можете ли вы объяснить по-английски, что вы пытаетесь сделать? Ваши запросы успешно выбирают группу записей, совокупная сумма которых меньше заданного веса, и упорядочивают их случайным образом. Это не кажется полезным.   -  person Gordon Linoff    schedule 20.05.2012
comment
Я пытаюсь выбрать 1 случайную строку для каждого запроса с учетом веса. Набор строк с более высоким весом должен появляться чаще, чем строка с меньшим весом. Вероятность появления веса 5 должна быть в 5 раз выше, чем, скажем, веса 1. Если этому сценарию соответствует несколько строк (строки с одинаковым весом), выберите один набор строк из этой группы. Что-нибудь быстрое и грязное подойдет, мне не нужно, чтобы это было статистически совершенным   -  person Patriotec    schedule 20.05.2012
comment
Пожалуйста, не добавляйте к заголовкам префиксы MSSQL и тому подобное. Вот для чего нужны теги.   -  person John Saunders    schedule 20.05.2012


Ответы (1)


Вы можете сделать это путем выборки из совокупной суммы, а не из записей. Идея состоит в том, чтобы взять кумулятивную сумму весов, затем взять случайное значение до максимального веса и, наконец, посмотреть, какая запись имеет кумулятивную сумму вокруг этого случайного значения. SQL выглядит так:

select top 1 t.*
from (select t.*, cumulative_sum(weight) as cumweight,
             sum(weight) over (partition by NULL) as totalweight
      from t
     ) t
where rand()*(totalweight+1) < cumweight
order by cumweight desc

Это создает совокупный вес, а затем создает случайную переменную до общей суммы весов. Выбирается последняя запись, совокупный вес которой меньше суммарного. «+1» просто для того, чтобы быть уверенным, что можно выбрать любую запись, даже последнюю.

В SQL Server 2012 вы можете рассчитать кумулятивную СУММ с помощью СУММ () по (разделение по NULL по порядку).

В SQL Server 2012 вы можете использовать: select top 1 t. * From (выберите t. , sum (weight) over (разделение по NULL по весу) как cumweight, sum (вес) over (раздел по NULL) как общий вес от t) t, где rand () (totalweight + 1) ‹порядок совокупного веса по совокупному весу по убыванию

К сожалению, этот синтаксис не поддерживается в SQL Server 2008. В этой базе данных вам нужно выполнить самосоединение, то есть запрос, который вы взяли из исходной статьи.

person Gordon Linoff    schedule 20.05.2012
comment
cumulative_sum (вес) как общий вес, sum (вес) over (разделение на NULL) как общий вес от t. кумулятивная_сумма. Это не функция. Как рассчитать совокупную сумму веса? - person Patriotec; 20.05.2012
comment
Извините, да, я использую для этого SQL 2012. Когда я пытаюсь запустить это, я получаю сообщение об ошибке «cumulative_sum» не является распознанным именем встроенной функции. - person Patriotec; 20.05.2012
comment
Cumulaitve_sum () была концептуальной идеей. Правильный синтаксис - SUM (var) over (разделение по NULL с помощью ‹пункта упорядочивания›). - person Gordon Linoff; 20.05.2012
comment
Вы потеряли меня, я переписал код и застрял на одном моменте. вы указываете совокупный вес в порядке по частям. Что я на самом деле ставлю вместо «кумулятивная_сумма (вес) как совокупный вес»? - person Patriotec; 20.05.2012
comment
Спасибо за помощь. Я выполнил несколько запросов, и пока все выглядит хорошо. Теперь я создам цикл и вставлю его во временную таблицу, чтобы посмотреть, как обстоят дела с распределением. - person Patriotec; 20.05.2012
comment
Я сделал цикл и 2000 раз вставлял в временную таблицу. К вашему сведению, не очень хорошее распределение с большими записями (или, если на то пошло, небольшими наборами данных). Этот запрос постоянно выбирает одни и те же наборы строк. Некоторые строки так и не были выбраны. Совсем не большой разброс. - person Patriotec; 20.05.2012