문제

테이블에서 다음 정보를 변환 할 수있는 단일 쿼리를 찾고 있습니다.

name:time    :state
a   :10:00 AM:login
b   :10:05 AM:login
a   :10:06 AM:chatting
a   :10:08 AM:Idle
b   :10:11 AM:chatting
a   :10:10 AM:Logout
b   :10:12 AM:Logout

이와 같은 것으로 (시간 범위가 오전 10 시부 터 오전 10시 15 분에 쿼리 기간으로)

name: State    :Duration
a   : chatting :2 Minutes 
a   : Idle     :2 Minutes
b   : chatting :1 Minute

SQL을 사용하여 만 수행 할 수 있습니까? Informix 버전 11.5를 사용하고 있습니다

도움이 되었습니까?

해결책

단일 SQL 문으로 수행 할 수 있습니다. 증거는 다음과 같습니다.

설정

CREATE TEMP TABLE eventtable
(
    name CHAR(3) NOT NULL,
    time DATETIME HOUR TO MINUTE NOT NULL,
    state CHAR(8) NOT NULL
);

INSERT INTO eventtable(name, time, state) VALUES('a', '10:00', 'login');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:05', 'login');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:06', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:08', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:11', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('a', '10:10', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('b', '10:12', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:01', 'login');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:02', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:03', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:04', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:05', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:06', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:07', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:08', 'Logout');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:09', 'login');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:11', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:12', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:13', 'chatting');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:14', 'Idle');
INSERT INTO eventtable(name, time, state) VALUES('c', '10:15', 'Logout');

올바른 쿼리

조건에 유의하십시오. 결과 테이블은 '로그인'과 첫 번째 이벤트 사이의 기간을 제외해야합니다. 또한 '로그 아웃'과 다음 이벤트 (아마도 '로그인') 사이의 기간을 제외해야합니다. 테이블 사이의 자체 교육 이름 열과 비대칭 결합 시각 열 ( '사용'<') 이벤트가 시간 순서대로 보장합니다. NOT가 존재하지 않으면 인접한 이벤트 만 고려되도록합니다. 하위 쿼리 사이에서 사용하는 것은 엔드 포인트가 포함되어 있기 때문에 실수입니다. r1.time 그리고 r2.time 범위에서 제외됩니다. 그 버그를 발견하는 데 몇 분이 걸렸습니다 (쿼리는 실행되었지만 줄은 없었지만 ?)!

SELECT r1.name, r1.state, r2.TIME - r1.TIME AS duration
    FROM eventtable r1, eventtable r2
    WHERE r1.name = r2.name
      AND r1.time < r2.time
      AND r1.state != 'login'
      AND r1.state != 'Logout'
      AND r1.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND r2.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND NOT EXISTS (SELECT 1 FROM eventtable r3
                            WHERE r3.time > r1.time AND r3.time < r2.time
                      AND r3.name = r1.name
                      AND r3.name = r2.name);

이것은 답을 생성합니다.

name state      duration
a    chatting   0:02
a    Idle       0:02
b    chatting   0:01

c    chatting   0:01
c    Idle       0:01
c    Idle       0:01
c    Idle       0:01
c    chatting   0:01
c    Idle       0:01
c    chatting   0:01
c    Idle       0:01

'기간'값은 간격 시간에서 분입니다. 몇 분 안에 값을 원한다면 값을 캐스트로 변환해야합니다 (최대 1440 분 또는 1 일 간격을 허용하기 위해 정밀도에 4를 사용하십시오. 데이터는 더 긴 시간 프레임에 대해 모호합니다) :

(r2.time - r1.time)::INTERVAL MINUTE(4) TO MINUTE

또는:

CAST (r2.time - r1.time AS INTERVAL MINUTE(4) TO MINUTE)

IBM Informix Dynamic Server (IDS)에는 시간 상수에 대한 동점 표기법이 매우 있습니다. 표준 SQL에서는 시간을 유형 및 시간 '10 : 00 : 00 '값으로 사용할 수 있지만 엄격한 표준 SQL에서는 초가 필요합니다. IDS는 DateTime 시간에서 분과 같이 사람들이 원하는 정확한 유형을 제공합니다. 또한 표준 SQL에 간격 분 (4)을 작성합니다. 'to minute'는 선택 사항이어야합니다.

잘못된 쿼리

Ray Hidayat의 답변에 대한 나의 의견에서, 나는 고려중인 사건이 인접한 지 확인하기 위해 서브 쿼리가 필요하다는 것을 지적했다. 다음은 출력에 START 및 END TIMES가 추가 된 것과 동일한 쿼리이며, Exiss 절은 누락 된 조항 (및 'DUPSE'로 이름이 변경됨 'Lapse')입니다.

SELECT r1.name, r1.state, r2.TIME - r1.TIME AS lapse,
       r1.time AS start, r2.time AS end
    FROM eventtable r1, eventtable r2
    WHERE r1.name = r2.name
      AND r1.time < r2.time
      AND r1.state != 'login'
      AND r1.state != 'Logout'
      AND r1.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE
      AND r2.time BETWEEN DATETIME(10:00) HOUR TO MINUTE
                      AND DATETIME(10:15) HOUR TO MINUTE;

이것은 답을 생성합니다.

name state     lapse start end
a    chatting   0:04 10:06 10:10
a    chatting   0:02 10:06 10:08
a    Idle       0:02 10:08 10:10
b    chatting   0:01 10:11 10:12
c    chatting   0:13 10:02 10:15
c    chatting   0:12 10:02 10:14
c    chatting   0:11 10:02 10:13
c    chatting   0:10 10:02 10:12
c    chatting   0:09 10:02 10:11
c    chatting   0:07 10:02 10:09
c    chatting   0:06 10:02 10:08
c    chatting   0:05 10:02 10:07
c    chatting   0:04 10:02 10:06
c    chatting   0:03 10:02 10:05
c    chatting   0:02 10:02 10:04
c    chatting   0:01 10:02 10:03
c    Idle       0:12 10:03 10:15
c    Idle       0:11 10:03 10:14
c    Idle       0:10 10:03 10:13
c    Idle       0:09 10:03 10:12
c    Idle       0:08 10:03 10:11
c    Idle       0:06 10:03 10:09
c    Idle       0:05 10:03 10:08
c    Idle       0:04 10:03 10:07
c    Idle       0:03 10:03 10:06
c    Idle       0:02 10:03 10:05
c    Idle       0:01 10:03 10:04
c    Idle       0:10 10:05 10:15
c    Idle       0:09 10:05 10:14
c    Idle       0:08 10:05 10:13
c    Idle       0:07 10:05 10:12
c    Idle       0:06 10:05 10:11
c    Idle       0:04 10:05 10:09
c    Idle       0:03 10:05 10:08
c    Idle       0:02 10:05 10:07
c    Idle       0:01 10:05 10:06
c    Idle       0:08 10:07 10:15
c    Idle       0:07 10:07 10:14
c    Idle       0:06 10:07 10:13
c    Idle       0:05 10:07 10:12
c    Idle       0:04 10:07 10:11
c    Idle       0:02 10:07 10:09
c    Idle       0:01 10:07 10:08
c    chatting   0:04 10:11 10:15
c    chatting   0:03 10:11 10:14
c    chatting   0:02 10:11 10:13
c    chatting   0:01 10:11 10:12
c    Idle       0:03 10:12 10:15
c    Idle       0:02 10:12 10:14
c    Idle       0:01 10:12 10:13
c    chatting   0:02 10:13 10:15
c    chatting   0:01 10:13 10:14
c    Idle       0:01 10:14 10:15

이는 사용자 'C'의 각 적격 시작 행이 각 적격 엔드 행과 일치하는 방법을 보여 주므로 많은 가짜 데이터를 제공합니다. 아님은 하위 쿼리가 시간 기반 쿼리를 다룰 때 일반적인 주제입니다. Snodgrass 's에서 이러한 작업에 대한 정보를 찾을 수 있습니다.SQL에서 시간 지향 응용 프로그램 개발"(PDF는 URL에서 온라인으로 제공) 및 날짜에 Darwen과 Lorentzos"시간 데이터 및 관계형 모델".

다른 팁

나는 그것이 SQL만을 사용하여 할 수 있다고 확신합니다. 쿼리를 내기 위해 시간이 많이 걸릴 것입니다. 내가 완료되면 편집 할 것입니다. 내가 생각하는 기본 단계는 먼저 각 항목을 취하고 다음 항목에 가입하여 다음 항목에 가입하여 시간 차이를 찾기 위해 빼면서 수행하는 시간을 먼저 계산하는 것입니다. 그러면 합계가있는 간단한 그룹은 쉽게 얻을 수 있습니다. 당신이 설명한 형태로.

편집 : 여기서 내가 생각해 낸 것

SELECT l.userid, l.state, SUM(t.minutes) AS duration
FROM Log l 
INNER JOIN (
    SELECT l1.id, (l2.time - l1.time) AS minutes
    FROM Log l1, Log l2
    WHERE l2.time == ( 
        -- find the next entry --
        SELECT TOP 1 ls.time
        FROM Log ls
        WHERE ls.Time > l1.Time && ls.userid = l1.userid
        ORDER BY ls.Time
    )
) t ON l.id == t.id
GROUP BY l.userid, l.state
ORDER BY l.userid

이것은 반-슈도 코드이며, 나는 모든 테이블 이름과 물건을 구성하고, 다른 한 번만 빼면 Datediff 함수를 사용하게 될 것입니다. 그 외에도, 나는 그것이 요점이라고 생각합니다. SQL은 가장 놀라운 언어 중 하나라고 생각합니다. 작은 코드로 거의 모든 것을 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top