4

작성/삽입 문을 추가하는 제안에 대해서는 Mike에게 감사드립니다.연속 된 일수의 '연속'행에 실행 횟수를 추가하는 방법

pid | date  | in_streak 
-------|-----------|---------- 
1  | 2014-10-1 | 1 
1  | 2014-10-2 | 2 
1  | 2014-10-3 | 3 
1  | 2014-10-5 | 1 
1  | 2014-10-7 | 1 
2  | 2014-10-2 | 1 
2  | 2014-10-3 | 2 
2  | 2014-10-4 | 3 
2  | 2014-10-6 | 1 

내가

에서 답변을 사용하려고했습니다 :

create table test (
    pid integer not null, 
    date date not null, 
    primary key (pid, date) 
); 

insert into test values 
    (1,'2014-10-1') 
, (1,'2014-10-2') 
, (1,'2014-10-3') 
, (1,'2014-10-5') 
, (1,'2014-10-7') 
, (2,'2014-10-1') 
, (2,'2014-10-2') 
, (2,'2014-10-3') 
, (2,'2014-10-5') 
, (2,'2014-10-7'); 

나는 그래서 결과과 같을 것이다 '일 현재의 행진에'는 새 열을 추가 할

그러나 올바른 결과를 얻으려면 다른 창 기능과 함께 dense_rank() 트릭을 사용하는 방법을 알아낼 수 없습니다.

+0

"pid는 고유합니다. 날짜는 없습니다." 그러나 데이터에 의하면 날짜는 고유하며 PID는 그렇지 않습니다. 어느 것이 맞는지? –

+0

여러 개의 PID가 동일한 날짜를 가질 수 있다는 점에서 날짜가 고유하지 않습니다. 나는 그 질문을 분명하게 할 것이다. – Ben

답변

8

건물 (열 이름과 SQL keyword "date" 사용하지.)

CREATE TABLE tbl(
    pid int 
, the_date date 
, PRIMARY KEY (pid, the_date) 
); 

쿼리

SELECT pid, the_date 
    , row_number() OVER (PARTITION BY pid, grp ORDER BY the_date) AS in_streak 
FROM (
    SELECT *, the_date - '2000-01-01'::date - row_number() 
      OVER (PARTITION BY pid ORDER BY the_date) AS grp 
    FROM tbl 
) sub 
ORDER BY pid, the_date; 

다른 date에서 date 감산이 integer을 수득 . 연속 일을 찾고 있기 때문에 모든 다음 행은 하나의만큼 커집니다. 그로부터 row_number()을 뺀다면, 전체 줄은 pid 당 같은 그룹 (grp)으로 끝납니다. 그런 다음 그룹당 숫자를 처리하는 것이 간단합니다.

grp은 두 개의 빼기로 계산됩니다.이 빼기는 가장 빠릅니다. 똑같이 빠른 대안은 다음과 같을 수 있습니다 :

the_date - row_number() OVER (PARTITION BY pid ORDER BY the_date) * interval '1d' AS grp 

하나의 곱하기, 하나의 빼기. 문자열 연결 및 캐스팅은 더 비쌉니다. EXPLAIN ANALYZE으로 테스트하십시오.

pid으로 파티션을 추가하고 모두 단계를 추가하는 것을 잊지 마십시오. 그렇지 않으면 우연히 구분해야하는 그룹을 혼합하게됩니다.

하위 쿼리를 사용하면 일반적으로 CTE보다 빠르기 때문에 하위 쿼리를 사용합니다. 일반 서브 쿼리가 할 수 없었던 것은 여기에 없습니다.

그리고 언급 했으니 여기서는 dense_rank()이 아니며이 필요하지 않습니다. 기본 row_number()이 작업을 수행합니다.

3

질문에 CREATE TABLE 문과 INSERT 문을 포함하면 더 많은주의를 얻게됩니다.

create table test (
    pid integer not null, 
    date date not null, 
    primary key (pid, date) 
); 

insert into test values 
(1,'2014-10-1'), (1,'2014-10-2'), (1,'2014-10-3'), (1,'2014-10-5'), 
(1,'2014-10-7'), (2,'2014-10-1'), (2,'2014-10-2'), (2,'2014-10-3'), 
(2,'2014-10-5'), (2,'2014-10-7'); 

원칙은 간단합니다. 별개의 연속 날짜에서 row_number()를 뺀 줄이 상수입니다. 상수로 그룹화하고 해당 결과에 대해 dense_rank()를 사용할 수 있습니다. 이 테이블

with grouped_dates as (
    select pid, date, 
     (date - (row_number() over (partition by pid order by date) || ' days')::interval)::date as grouping_date 
    from test 
) 
select * , dense_rank() over (partition by grouping_date order by date) as in_streak 
from grouped_dates 
order by pid, date 
 
pid date   grouping_date in_streak 
-- 
1 2014-10-01 2014-09-30  1 
1 2014-10-02 2014-09-30  2 
1 2014-10-03 2014-09-30  3 
1 2014-10-05 2014-10-01  1 
1 2014-10-07 2014-10-02  1 
2 2014-10-01 2014-09-30  1 
2 2014-10-02 2014-09-30  2 
2 2014-10-03 2014-09-30  3 
2 2014-10-05 2014-10-01  1 
2 2014-10-07 2014-10-02  1 
+0

이것을 실행하면 첫 번째 PID 그룹에서 휴식을 취하지 않습니다. 즉 줄무늬가 계속됩니다. Erwin에서 제안한대로 두 번째 선택 영역에 여분의 pid 파티션을 추가하면 예상대로 작동합니다. – Ben

+0

정말 도움이됩니다. 감사합니다. –