2010-01-02 2 views
2

Я следующий SQL запрос, который выбирает некоторые результаты из моей таблицы:PostgreSQL: Выбор N результата в группе по запросу

select avg(c3), count(c3), std 
from ssims where obraz = 'lena' group by std order by std 

Но у меня есть различное количество тестов, выполненных для различных значений Std, поэтому она возвращает меня что-то вроде этого:

0.906176136363636;44;5 
0.881669302325582;43;10 
0.855873409090909;44;15 
0.829195813953488;43;20 
0.802071590909091;44;25 
0.774523720930233;43;30 
0.747213636363636;44;35 
0.720115581395349;43;40 
0.694712954545455;44;45 
0.668683255813953;43;50 

то, что я хотел бы сделать, это выбрать среднее значение постоянной (т.е. 20) количество результатов для каждого станд значения. Поэтому после такого запроса второй столбец будет равен 20 для каждой строки.

Как это сделать? Я попробовал пределы и сверху, но без успеха

+0

Какие 20 строк следует использовать? –

+0

Он должен выбрать 20 строк (независимо от того, какое значение) для каждого значения std – Gacek

+0

Если вы просто смотрите на случайное подмножество и делаете среднее значение, почему имеет значение, если вы делаете 20 или более строк? Я вижу, как слишком мало строк даст вам неправильный номер, но слишком много? –

ответ

6

В PostgreSQL 8.3:

SELECT a[1] AS avg_std, a[2] AS cnt_std, std 
FROM (
     SELECT (
       SELECT ARRAY[AVG(c3) , COUNT(*)] 
       FROM (
         SELECT c3 
         FROM ssims si 
         WHERE obraz = 'lena' 
           AND si.std = so.std 
         ORDER BY 
           id 
         LIMIT 20 
         ) q 
       ) a 
     FROM (
       SELECT DISTINCT std 
       FROM ssims 
       WHERE obraz = 'lena' 
       ) so 
     ) q 

Это будет рассчитывать как AVG и COUNT в одном сканирования индекса для каждого станд.

Создайте составной индекс на (obraz, std, id), чтобы это работало быстро.

В PostgreSQL 8.4:

SELECT AVG(c3), COUNT(*), std 
FROM (
     SELECT std, c3, ROW_NUMBER() OVER (PARTITION BY std ORDER BY id) AS rn 
     FROM ssims 
     WHERE obraz = 'lena' 
     ) q 
WHERE rn <= 20 
GROUP BY 
     std 
+0

Версия 8.4 Работает как шарм! Спасибо! – Gacek

0

Предполагая, что ваш ssims таблица имеет уникальный столбец ID, который я назвал id в моем примере вы можете сделать следующее:

select avg(c3), count(c3), std from ssims where id in 
    (select id from ssims where obraz = 'lena' LIMIT 20) 
    group by std order by std; 
+0

Да, у него такой столбец, но это не работает. Существует ошибка, так как std также должен быть выбран в подзапросе при gouping. Сообщение об ошибке: ОШИБКА: столбец «ssims.id» должен появиться в предложении GROUP BY или использоваться в агрегатной функции – Gacek

+0

Вы можете удалить группу по инструкции из внутреннего выбора и применить к внешнему выбору, как я уже сделал , В зависимости от результатов, которые вам нужны, вы также можете просто добавить id в группу по заявлению во внутреннем выборе. –

+0

nope, он выберет только 20 элементов, а не 20 элементов для каждого значения std – Gacek

0

Если вы находитесь на 8.4, вы должны иметь возможность сделать это с помощью функции окна. (Не уверен, что станд часть, но я уверен, что вы можете добавить, что еще) что-то вроде этого (непроверенные, так что вам, возможно, придется изменить некоторые вещи):

SELECT std,avg(c3), count(c3) 
FROM (
SELECT std, c3, row_number() OVER (
    PARTITION BY std ORDER BY random()) 
) foo 
WHERE row_number <= 20 
GROUP BY std 
ORDER BY std 

Если вы не волнует, что вы действительно получаете случайное подмножество, вы можете удалить часть ORDER BY random(), и она даст вам «почти случайный».

+0

Он по-прежнему возвращает ошибку (без столбца std), даже в 8.4 – Gacek

+0

Ух, теперь я вижу, что в запросе отсутствует «FROM ssims». Он должен иметь это перед частью «) foo». Это то, что я имел в виду с «вам, возможно, придется что-то корректировать» –

Смежные вопросы