2012-04-22 3 views
19

Я пытаюсь ранжировать подмножество данных внутри таблицы, но я думаю, что я делаю что-то неправильно. Я не могу найти много информации о функции rank() для postgres, возможно, я искал не то место. В любом случае:Как оценивать в postgres-запросе

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

select cluster_id,feed_id,pub_date,rank 
from (select feed_id,pub_date,cluster_id,rank() 
    over (order by pub_date asc) from url_info) 
as bar where cluster_id = 9876 and feed_id = 1234; 

Я моделирующий это после того, как следующий StackOverflow сообщение: postgres rank

Причина, я думаю, что я делаю что-то неправильно, что есть в url_info только 39 строк, которые находятся в cluster_id 9876, и этот запрос длился 10 минут и больше не возвращался. (на самом деле повторно запустил его довольно долгое время, и он не дал никаких результатов, но есть строка в кластере 9876 для id 1234). Я ожидаю, что это скажет мне что-то вроде «id 1234 было пятым по заданным критериям». возвращает относительный ранг в соответствии с моими ограничениями запроса, правильно?

Это Postgres 8.4 кстати.

+3

Вы хотите, чтобы ранг относился к чему? все записи (это ваш запрос выше спрашивает и, вероятно, почему он занимает слишком много времени)? набор записей, выбранных предикатом? некоторые другие группировки? Предложение 'over' должно указывать' partition by', если вы не хотите ранжировать все строки. [Вот учебник по функциям окна] (http://www.postgresql.org/docs/8.4/static/tutorial-window.html) – dbenhur

+0

Я хочу ранжировать относительно pub_date. Возможно, я могу объяснить немного лучше: url_info имеет тысячи URL-адресов. 39 из них объединяют кластер 9876. Выбрав только URL-адрес, который является членом 9876 (url может быть ТОЛЬКО членом одного кластера), я хочу ранжировать URL-адрес (который составляет кластер 9876) в порядке, основанном на pub_date.Я все еще использую разделы, основанные на функциях окна для этого? Я посмотрел URL-адрес, который вы отправили, и похоже, что это относится к элементам ранжирования после того, как я вычислил какое-то значение, которое я здесь не делаю. – WildBill

ответ

26

, помещая функцию ранга() в подзапрос и не указав PARTITION BY в операторе над или любого предиката в этом подзапросе ваш запрос запрашивает присвоение ранга по всей таблице url_info, упорядоченной по адресу pub_date. Вероятно, поэтому она выполнялась до тех пор, пока она не была ранжирована по всему url_info, Pg должен сортировать всю таблицу по pub_date, что приведет к если таблица очень большая.

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

select 
    cluster_id 
,feed_id 
,pub_date 
,rank() over (order by pub_date asc) as rank 
from url_info 
where cluster_id = 9876 and feed_id = 1234; 

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

select ranked.* 
from (
    select 
    cluster_id 
    ,feed_id 
    ,pub_date 
    ,rank() over (order by pub_date asc) as rank 
    from url_info 
    where cluster_id = 9876 
) as ranked 
where feed_id = 1234; 
+0

'rank() over (order by pub_date asc), поскольку rank' является избыточным , поскольку имя столбца по умолчанию - это имя функции – isapir

+0

@isapir Возможно, так, но это не сильное обещание; из [docs] (https://www.postgresql.org/docs/current/static/sql-select.html#SQL-SELECT-LIST): «В более сложных случаях функция или имя типа ** могут быть * * используется, или система может отказаться от сгенерированного имени, такого как столбец? " – dbenhur

5

Sharing другой пример DENSE_RANK() PostgreSQL. Найдите пример 3-го студента. Reference taken from this blog:

Создание таблицы с данными выборки:

CREATE TABLE tbl_Students 
(
    StudID INT 
    ,StudName CHARACTER VARYING 
    ,TotalMark INT 
); 

INSERT INTO tbl_Students 
VALUES 
(1,'Anvesh',88),(2,'Neevan',78) 
,(3,'Roy',90),(4,'Mahi',88) 
,(5,'Maria',81),(6,'Jenny',90); 

Использование DENSE_RANK(), Вычислить RANK студентов:

;WITH cteStud AS 
(
    SELECT 
     StudName 
     ,Totalmark 
     ,DENSE_RANK() OVER (ORDER BY TotalMark DESC) AS StudRank 
    FROM tbl_Students 
) 
SELECT 
    StudName 
    ,Totalmark 
    ,StudRank 
FROM cteStud 
WHERE StudRank <= 3; 

Результат:

studname | totalmark | studrank 
----------+-----------+---------- 
Roy  |  90 |  1 
Jenny |  90 |  1 
Anvesh |  88 |  2 
Mahi  |  88 |  2 
Maria |  81 |  3 
(5 rows) 
Смежные вопросы