2017-01-09 5 views
0

У меня есть таблица с pk и dept столбцами:PostgreSQL - Как выбрать первую последовательную группу, имеющую одинаковое значение

pk dept 
------- 
27 A 
29 A 
30 B 
31 B 
33 A 

Мне нужно выбрать первой последовательной группы, то есть первый последующий набор строки все имеют один и то же dept значения, когда таблица упорядочена pk, то есть ожидаемый результат:

pk dept 
------- 
27 A 
29 A 

В моем примере есть 3 последовательных группы (АА, ВВ nd A). Размер группы неограничен (может быть больше 2).

+1

Вы создали этот новый термин «Последовательная группа» (из которого вы хотите первыми) и даже выделите его жирным шрифтом, но я не вижу определения. Является ли «Последовательная группа» набором из двух записей или набором из по меньшей мере двух записей перед изменением PK или что-то еще? – JNevill

ответ

2

Следующий запрос должен делать то, что вы хотите (я назвал вашу таблицу ТХ):

SELECT * 
FROM tx t1 
WHERE NOT EXISTS (
    SELECT * 
    FROM tx t2 
    WHERE t2.dept <> t1.dept 
    AND t2.pk < t1.pk); 

Идея заключается в том, чтобы искать кортежей, такие, что ни один кортеж с меньшей рк и другой отдел не существует ,

  • Сохранены первые два кортежа;
  • Корзины B выпадают из-за первых двух кортежей;
  • Последний Кортеж отбрасывается из-за B кортежей.
-2

Я не уверен, если я понимаю ваш вопрос, но для первого pk каждого dept вы можете попробовать это:

select min(pk) as pk, 
     dept 
from your_table 
group by dept 
0

Помнит о хранимых функциях. В отличие от окна с помощью функции его позволяет избежать чтения всей таблицы:

--drop function if exists foo(); 
--drop table if exists t; 
create table t(pk int, dep text); 
insert into t values(27,'A'),(29,'A'),(30,'B'),(31,'B'),(33,'A'); 

create function foo() returns setof t language plpgsql as $$ 
declare 
    r t; 
    p t; 
begin 
    for r in (select * from t order by pk) loop 
    if p is null then 
     p := r; 
    end if; 
    exit when p.dep is distinct from r.dep; 
    return next r; 
    end loop; 
    return; 
end $$; 

select * from foo(); 
0

Ее немного сложным и возможно, permformance плохой, но вы можете добиться того, что вы хотите с ниже код. Есть четыре операции:

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

Надеюсь, это поможет.

SELECT fourthOperation.pk, 
     fourthOperation.dept 
FROM (SELECT thirdOperation.pk, 
       thirdOperation.dept, 
       DENSE_RANK() OVER (ORDER BY thirdOperation.spreadedIdGroup) denseIdGroup 
     FROM (SELECT secondOperation.*, 
         NVL(idGroup, LAG(secondOperation.idGroup IGNORE NULLS) OVER (ORDER BY secondOperation.numRow)) spreadedIdGroup 
       FROM (SELECT firstOperation.*, 
          CASE WHEN LAG(firstOperation.rankRow) OVER (ORDER BY firstOperation.numRow) = firstOperation.rankRow 
           THEN NULL 
           ELSE firstOperation.numRow 
           END idGroup 
         FROM (SELECT yourTable.*, 
            ROW_NUMBER() OVER (ORDER BY PK) AS numRow, 
            DENSE_RANK() OVER (ORDER BY DEPT) AS rankRow 
           FROM ABORRAR yourTable) firstOperation) secondOperation) thirdOperation) fourthOperation 
WHERE fourthOperation.denseIdGroup = 1         
+0

Первое предложение SELECT должно быть SELECT pk, dept вместо SELECT * ;-) Кроме этого, я соглашаюсь на «немного сложную» часть: D Хорошие навыки SQL, хотя! –

+0

Я просто нашел ваше решение неправильным, так как предполагает, что таблица кластеризована на столбце pk. Если я добавлю кортеж (1, «A»), только ваш кортеж будет найден вашим решением, а op хочет 1, 27 и 29. –

+0

Спасибо за ваш комментарий, но OP sais «когда таблица заказана pk» и хочет только первую группу подряд, чтобы мое решение было правильным. Более того, он хочет всю строку, а не только pk. – cmoron