문제
테이블에서 다음 정보를 변환 할 수있는 단일 쿼리를 찾고 있습니다.
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은 가장 놀라운 언어 중 하나라고 생각합니다. 작은 코드로 거의 모든 것을 할 수 있습니다.