2017-10-26 5 views
1

이것은 내 첫 번째 질문이며이 항목을 어떤 항목으로 분류할지 모르기 때문에이 질문을 게시하기 전에 검색을 수행하지 않았습니다.SQL이 이전 데이터를 기반으로 피벗 함

이것은 SQL과 관련된 질문입니다. 필자는 피벗 (Pivot)이 더 친숙한 데이터 출력을 얻기 위해 필요한 데이터라고 생각합니다.

ID, 사용자 이름, 상태, 날짜 시간 각각 4 개의 열 테이블이 있습니다. 상태는 로그인 및 로그 아웃과 같은 사용자 작업을 결정합니다.

ID Username Status DateTime 
1 A   0  2017-10-20 05:00:00 
2 A   0  2017-10-20 07:23:10 
3 B   0  2017-10-20 07:24:45 
4 A   1  2017-10-20 09:50:55 
5 A   0  2017-10-20 13:00:56 
6 B   1  2017-10-20 17:13:28 
7 B   0  2017-10-20 17:50:47 
8 A   1  2017-10-20 21:38:17 
9 A   0  2017-10-20 21:38:19 
10 B   1  2017-10-20 21:40:02 

나는 로그인으로 Status0과 상태 1을 필터링하고 로그 아웃 할 필요하므로, 어떠한 Status0 사이에

ID Username Status DateTime 
1 A   0  2017-10-20 05:00:00 
2 A   0  2017-10-20 07:23:10 
4 A   1  2017-10-20 09:50:55 

Username Status0    Status1 
A   2017-10-20 05:00:00 2017-10-20 09:50:55 

하고 다음 'A'결과 것

무시 될 것이다 마지막 Status1 (2017-10-20 09:50:55)보다 크거나 같은 Status0의 DateTime을 검색하고 데이터 끝까지

내가 아래로 포맷 할 필요가있는 엔드 데이터 :

Username Status0    Status1 
A   2017-10-20 05:00:00 2017-10-20 09:50:55 
B   2017-10-20 07:24:45 2017-10-20 17:13:28 
A   2017-10-20 13:00:56 2017-10-20 21:38:17 
B   2017-10-20 17:50:47 2017-10-20 21:40:02 
A   2017-10-20 21:38:19 null 

내가 어떻게이 결과를 얻을 수 있습니다? 내 논리는 재귀 적으로 Status1을 비교하고 다음 Status0을 찾아야한다고 말하지만 SQL 쿼리에 넣는 방법을 모르겠습니다.

도움을 주시면 감사하겠습니다. 전에 고마워.

편집 : SQL Server 2008을 사용 중입니다.

답변

0

흠. (apply를 사용하여) 다음의 상태 (1)를 검색 한 후 집계 :이 모든 상태를 한 날짜 당신에게 행을 줄 것이다

select username, 
     min(datetime) as status_0_datetime, 
     status_1_datetime 
from (select t.*, t2.datetime as status_1_datetime 
     from t outer apply 
      (select top 1 t2.* 
      from t t2 
      where t2.username = t.username and t2.status = 1 and 
        t2.datetime > t.datetime 
      order by t2.datetime desc 
      ) t2 
     where t.status = 0 
    ) t 
group by username, status_1_datetime 
order by username, min(datetime); 

여기에 한 가지 방법입니다.

+0

그것은 특정 날짜가 상태가없는 가능성이 매우 옳지 않다 http://dbfiddle.uk/?rdbms=sqlserver_2016&fiddle=80f8aae9c95f042bf9c9ed17c3350e76 –

+0

입니다 약간 더 효율적으로 할 수있다 1 데이터, 그래서 내가 정확히 무엇을 찾고 있어요. –

0

다음 방법을 시도해보십시오. LAG을 사용하여 사용자 상태에서 반복되는 0을 제거한 다음 ROW_NUMBER을 사용하여 사용자의 로그인/로그 아웃을 적절하게 그룹화합니다.

select tt.username, 
    MAX(CASE WHEN status = 0 THEN tt.datetime END) status0, 
    MAX(CASE WHEN status = 1 THEN tt.datetime END) status1 
from 
(
    select *, 
     row_number() over (partition by username, status order by datetime) rn 
    from 
    (
     select *, lag(status) over (partition by username order by datetime) prevstatus 
     from your_table 
    ) t 
    where not(t.status = 0 and t.prevstatus = 0) or t.prevstatus is null -- this is to remove repeating 0 
) tt 
group by tt.username, tt.rn 

demo

편집 :이 솔루션은 SQL 서버 2008 R2를위한해야하므로가 좋아, 따라서 더 LAG이 없습니다. 확인

select tt.username, 
    MAX(CASE WHEN status = 0 THEN tt.datetime END) status0, 
    MAX(CASE WHEN status = 1 THEN tt.datetime END) status1 
from 
(
    select *, 
     row_number() over (partition by username, status order by datetime) rn 
    from 
    (
     select * 
     from your_table yt1 
     where status = 1 or 
      not exists(
       select 1 
       from your_table yt2 
       where yt2.status = 0 and 
        yt2.username = yt1.username and 
        yt2.datetime = (
         select max(yt3.datetime) 
         from your_table yt3 
         where yt3.datetime < yt1.datetime and 
          yt3.username = yt1.username 
        ) 
      ) 
    ) t 
) tt 
group by tt.username, tt.rn 

demo

하고는 외부 조인 대신에 따라 하위 쿼리의 GROUP BY을 사용하는 마지막 버전이 : 그럼 NOT EXISTS를 사용하여 해결할 수있다, 그러나, 그것은 매우 읽을 수 없습니다. 따라서 어떤 경우

select tt.username, 
    MAX(CASE WHEN status = 0 THEN tt.datetime END) status0, 
    MAX(CASE WHEN status = 1 THEN tt.datetime END) status1 
from 
(
    select *, 
     row_number() over (partition by username, status order by datetime) rn 
    from 
    (
     select xt.*, yt.status joinstatus 
     from your_table yt 
     right join (
      select yt1.id, yt1.datetime, yt1.username, yt1.status, max(yt2.datetime) prevdatetime 
      from your_table yt1 
      left join your_table yt2 on yt1.datetime > yt2.datetime and 
            yt2.username = yt1.username and 
            yt1.status = 0 
      group by yt1.id, yt1.datetime, yt1.username, yt1.status 
     ) xt on yt.datetime = xt.prevdatetime and yt.username = xt.username and xt.status = yt.status 
    ) t 
    where t.joinstatus is null 
) tt 
group by tt.username, tt.rn 
+0

데모에서 유망한이 표정이지만 'LAG'과 관련하여 오류가 발생했습니다. 인식 된 내장 함수 이름이 아닙니다 ... –

+0

죄송합니다. 나는'LAG'가 SQL2012 이상을위한 함수라는 것을 알았습니다. 저는 SQL Server 2008 R2를 사용하고 있습니다.이 LAG에 대한 대안을 제시 할 수 있습니까? –