Выборка из Oracle, нужно точное количество результатов (Образец статьи)

Я пытаюсь получить случайную выборку населения из базы данных Peoplesoft. Поиски в Интернете привели меня к мысли, что предложение Sample в операторе select может быть жизнеспособным вариантом для нас, однако у меня возникли проблемы с пониманием того, как предложение Sample определяет количество возвращаемых образцов. Я просмотрел документацию оракула, найденную здесь: http://docs.oracle.com/cd/E11882_01/server.112/e26088/statements_10002.htm#i2065953

Но приведенная выше ссылка говорит только о синтаксисе, используемом для создания образца. Причина моего вопроса в том, что мне нужно понять, как процент выборки определяет возвращаемый размер выборки. Кажется, что он применяет случайное число к проценту, который вы запрашиваете, а затем использует начальное число для подсчета каждых «n» записей. Наше требование состоит в том, чтобы мы извлекали точное количество выборок, например, чтобы они были выбраны случайным образом и чтобы они представляли всю таблицу (или, по крайней мере, группу данных, которую мы выбираем с помощью фильтров).

В совокупности из 10200 элементов, если мне нужна выборка из примерно 100 элементов, я мог бы использовать это утверждение:

SELECT * FROM PS_LEDGER SAMPLE(1) --1 % of my total population
WHERE DEPTID = '700064' 

Однако нам нужно получить точное количество выборок (в данном случае 100), чтобы я мог выбрать размер выборки, который почти всегда возвращает больше, чем мне нужно, а затем обрезать его IE

SELECT Count(*) FROM PS_LEDGER SAMPLE(2.5) --this percent must always give > 100 items
WHERE DEPTID = '700064' and rownum < 101

Меня беспокоит то, что моя выборка не будет единообразно представлять все население. Например, если функция выборки просто извлекает каждую N запись после того, как она создает свое собственное случайно сгенерированное начальное число, то выбор rownum ‹ 101 отрезает все записи, выбранные в нижней части таблицы. То, что я ищу, - это способ вытащить из таблицы ровно 100 записей, которые выбираются случайным образом и достаточно репрезентативны для всей таблицы. Пожалуйста помоги!!


person user2284134    schedule 15.04.2013    source источник
comment
Без order by у rownum на самом деле нет понятия «нижняя часть таблицы». Вы можете явно упорядочить свой образец по dbms_random.value перед применением фильтра rownum (во внешнем select), а если это небольшая таблица, вам может вообще не понадобиться образец?   -  person Alex Poole    schedule 16.04.2013
comment
что вы имеете в виду под словом "представитель"? в общем случае порядок записей в результирующем наборе запроса без предложения order by является произвольным. однако вы можете явно рандомизировать его, заказав его с помощью dbms_random. пример: select * from ps_ledger where deptid ='7000064' order by dbms_random.value.   -  person collapsar    schedule 16.04.2013


Ответы (3)


Заимствуя таблицу примеров jonearles, я вижу то же самое (в 11gR2 на образе разработчика OEL), обычно получая значения для a, сильно смещенные в сторону 1; при небольших размерах выборки я иногда вообще не вижу. С дополнительным шагом рандомизации/ограничения, о котором я упоминал в комментарии:

select a, count(*) from (
    select * from test1 sample (1)
    order by dbms_random.value
)
where rownum < 101
group by a;

... с тремя прогонами я получил:

         A   COUNT(*)
---------- ----------
         1         71
         2         29

         A   COUNT(*)
---------- ----------
         1        100

         A   COUNT(*)
---------- ----------
         1         64
         2         36

Да, 100% действительно вернулись как 1 при втором запуске. Сам перекос кажется довольно случайным. Я пробовал с модификатором block, который, казалось, не имел большого значения, возможно, удивительно - я мог подумать, что в этой ситуации будет хуже.

Это, вероятно, будет медленнее, особенно для небольших размеров выборки, поскольку оно должно охватывать всю таблицу; но дает мне довольно четные разделения довольно последовательно:

select a, count(*) from (
    select a, b from (
        select a, b, row_number() over (order by dbms_random.value) as rn
        from test1
    )
    where rn < 101
)
group by a;

С тремя прогонами я получил:

         A   COUNT(*)
---------- ----------
         1         48
         2         52

         A   COUNT(*)
---------- ----------
         1         57
         2         43

         A   COUNT(*)
---------- ----------
         1         49
         2         51

... который выглядит немного здоровее. YMMV, конечно.


В этой статье об Oracle рассматриваются некоторые методы выборки, и вы также можете оценить подход ora_hash , и стратифицированную версию, если ваши данные распространяются и ваши требования к «репрезентативности» требуют этого.

person Alex Poole    schedule 16.04.2013

Вы не можете доверять SAMPLE возврату действительно случайного набора строк из таблицы. Алгоритм, по-видимому, основан на физических свойствах стола.

create table test1(a number, b char(2000));

--Insert 10K fat records.  A is always 1.
insert into test1 select 1, level from dual connect by level <= 10000;

--Insert 10K skinny records.  A is always 2.
insert into test1 select 2, null from dual connect by level <= 10000;

--Select about 10 rows.
select * from test1 sample (0.1) order by a;

Запустите последний запрос несколько раз, и вы почти никогда не увидите двойки. Это может быть точной выборкой, если вы измеряете по байтам, а не по строкам.

Это крайний пример искаженных данных, но я думаю, этого достаточно, чтобы показать, что RANDOM не работает так, как следует из руководства. Как уже предлагали другие, вы, вероятно, захотите ORDER BY DBMS_RANDOM.VALUE.

person Jon Heller    schedule 16.04.2013

Я заморачивался с похожим вопросом. Во-первых, я устанавливаю размер выборки для разных слоев. В вашем случае только один. ('700064'). Итак, в предложении with или временной таблице я сделал это:

Select DEPTID, Count(*) SAMPLE_ONE 
FROM PS_LEDGER  Sample(1)
WHERE DEPTID = '700064' 
Group By DEPTID

Это говорит вам о том, какие записи следует ожидать в 1% выборке. Назовем это TABLE_1

Затем я сделал это:

Select 
Ceil (Rank() over (Partition by DEPTID Order by DBMS_RANDOM.VALUE)
            / (Select SAMPLE_ONE From TABLE_1) STRATUM_GROUP
,A.*
FROM PS_LEDGER 

Сделайте это другой таблицей. То, что вы получаете, - это наборы случайных выборок размером ок. 1% от размера.

Таким образом, если ваша исходная таблица содержит 1000 записей, вы получите 100 наборов случайных выборок по 10 элементов в каждом наборе.

затем вы можете выбрать один из них случайным образом для тестирования.

Не уверен, что я объяснил это очень хорошо, но это сработало для меня. У меня было 168 Stratum Setup на столе с более чем 10Mil записями, которые работали достаточно хорошо.

Если вам нужно больше объяснений или вы можете улучшить это, пожалуйста, не стесняйтесь.

С уважением

person Quimbyf    schedule 17.12.2015