아래와 같은 DB 테이블이 있다. id_person과 id_class를 연결하는 relation 테이블이다. 반이 변하는 것을 기록해 누적한다.
보면 알 수 있겠지만, 1번 id_person은 2반이었다가 4반이었다가 1반이 됐다.
2번 id_person은 3반이었다가 1반이 됐다.
id | id_person | id_class | date_written |
53 | 1 | 1 | 2012-04-05 16:40 |
50 | 1 | 4 | 2012-04-05 16:02 |
1 | 1 | 2 | 2012-03-30 17:56 |
2 | 2 | 3 | 2012-03-30 17:56 |
51 | 2 | 1 | 2012-04-05 16:36 |
3 | 3 | 4 | 2012-03-30 17:56 |
52 | 3 | 1 | 2012-04-04 16:37 |
4 | 4 | 5 | 2012-03-30 17:56 |
5 | 5 | 6 | 2012-03-30 17:56 |
6 | 6 | 7 | 2012-03-30 17:56 |
7 | 7 | 1 | 2012-03-30 17:56 |
8 | 8 | 2 | 2012-03-30 17:56 |
9 | 9 | 3 | 2012-03-30 17:56 |
자, 그런데 지금 뽑으려는 데이터는 각 id_person 이 지금 몇 반인가 하는 거다.
서브쿼리로 하면 되지만…
이 테이블만을 바탕으로 그걸 뽑을 수 있을까? 있었다. 아래처럼 쿼리를 사용하는 거다.
SELECT p.* FROM `person_class_relation_table` AS p WHERE date_written=(SELECT MAX(date_written) FROM person_class_relation_table WHERE id_person = p.id_person)
이렇게 서브쿼리를 사용하면 구할 수 있다. 그런데 목록이 많아지면 심각한 성능 저하 현상이 벌어질 거다.
질문 – 서브쿼리를 사용하지 않고 구할 수 있는 방법은?
서브쿼리를 사용하지 않고 구할 수 있는 방법은 뭐가 있을까?
내가 시도한 방법은 아래 쿼리다.
SELECT *, MAX(date_written) FROM person_class_relation_table GROUP BY id_person
이렇게 하니까 친절하게 id_person으로 그룹이 지어져 나왔고, date_written 항목은 다른 데이터들과 아무런 상관없이 그냥 최고값만 나왔다. 즉, id_person 1번은 1반이어야 하는데 2반이라고 나왔다. 그런데 date_written은 최신값. OTL;; 역시 GROUP BY는 id_person을 기준으로 그룹만 지어 주는 놈이었던 것이야…
다음으로는 이렇게 해 봤는데 작동하지 않았다.
SELECT * FROM person_class_relation_table GROUP BY id_person WHERE date_written = MAX(date_written)
4번 줄이 오류 표시됐다. 저렇게 못 쓴다는 에러가 나온 거다 그냥.
여튼간에, 그래서 고수분들께 질문드린다. 내가 MySQL에 정말 취약하다는 것을 새삼 느끼면서 질문한다.
이 경우 대체 어떻게 해야 할까?! (같은 내용을 PHP School에 질문했다.)
PHPSchool에서 풀잎 님이 해 준 답변
서브쿼리 없이 구하는 방법은 없을 것 같습니다.
차라리 상태필드를 하나 더 입력하여
insert시 새로운 데이타는 상태 필드 = 1 로 입력하고,
동일 id_person이 존재하면 과거 데이타의 상태필드 = 0으로 update 시키는 것이 바람직해 보입니다.
그럼 굳이 group by를 하지 않더라도 where 상태필드 = 1 만으로도 원하는 효과를 얻을 수 있으리라 봅니다.물론 select가 더 빈번하게 일어나고 update?는 자주 일어나지 않는다는 조건하에서 이야기입니다.
이렇게 하는 게 나을 것 같다.
아래는 table 생성 쿼리다. 참고하면 된다.
-- -- 테이블 구조 `person_class_relation_table` -- CREATE TABLE IF NOT EXISTS `person_class_relation_table` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id', `id_person` int(11) NOT NULL COMMENT 'id_person', `id_class` int(11) NOT NULL COMMENT 'id_class', `date_written` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '입력일시', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=54 ; -- -- 테이블의 덤프 데이터 `person_class_relation_table` -- INSERT INTO `person_class_relation_table` (`id`, `id_person`, `id_class`, `date_written`) VALUES (1, 1, 2, '2012-03-30 17:56:58'), (2, 2, 3, '2012-03-30 17:56:58'), (3, 3, 4, '2012-03-30 17:56:58'), (4, 4, 5, '2012-03-30 17:56:58'), (5, 5, 6, '2012-03-30 17:56:58'), (6, 6, 7, '2012-03-30 17:56:58'), (7, 7, 1, '2012-03-30 17:56:58'), (8, 8, 2, '2012-03-30 17:56:58'), (9, 9, 3, '2012-03-30 17:56:58'), (10, 10, 4, '2012-03-30 17:56:58'), (11, 11, 5, '2012-03-30 17:56:58'), (12, 12, 6, '2012-03-30 17:56:58'), (13, 13, 7, '2012-03-30 17:56:58'), (14, 14, 1, '2012-03-30 17:56:58'), (15, 15, 2, '2012-03-30 17:56:58'), (16, 16, 3, '2012-03-30 17:56:58'), (17, 17, 4, '2012-03-30 17:56:58'), (18, 18, 5, '2012-03-30 17:56:58'), (19, 19, 6, '2012-03-30 17:56:58'), (20, 20, 7, '2012-03-30 17:56:58'), (21, 21, 1, '2012-03-30 17:56:58'), (22, 22, 2, '2012-03-30 17:56:58'), (23, 23, 3, '2012-03-30 17:56:58'), (24, 24, 4, '2012-03-30 17:56:58'), (25, 25, 5, '2012-03-30 17:56:58'), (26, 26, 6, '2012-03-30 17:56:58'), (27, 27, 7, '2012-03-30 17:56:58'), (28, 28, 1, '2012-03-30 17:56:58'), (29, 29, 2, '2012-03-30 17:56:58'), (30, 30, 3, '2012-03-30 17:56:58'), (31, 31, 4, '2012-03-30 17:56:58'), (32, 32, 5, '2012-03-30 17:56:58'), (33, 33, 6, '2012-03-30 17:56:58'), (34, 34, 7, '2012-03-30 17:56:58'), (35, 35, 1, '2012-03-30 17:56:58'), (36, 36, 2, '2012-03-30 17:56:58'), (37, 37, 3, '2012-03-30 17:56:58'), (38, 38, 4, '2012-03-30 17:56:58'), (39, 39, 5, '2012-03-30 17:56:58'), (40, 40, 6, '2012-03-30 17:56:58'), (41, 41, 7, '2012-03-30 17:56:58'), (42, 42, 1, '2012-03-30 17:56:58'), (43, 43, 2, '2012-03-30 17:56:58'), (44, 44, 3, '2012-03-30 17:56:58'), (45, 45, 4, '2012-03-30 17:56:58'), (46, 46, 5, '2012-03-30 17:56:58'), (47, 47, 6, '2012-03-30 17:56:58'), (48, 48, 7, '2012-03-30 17:56:58'), (49, 49, 1, '2012-03-30 17:56:58'), (50, 1, 4, '2012-04-05 16:02:07'), (51, 2, 1, '2012-04-05 16:36:49'), (52, 3, 1, '2012-04-04 16:37:09'), (53, 1, 1, '2012-04-05 16:40:25');
댓글 남기기