MySQL에서는 UNION 연산자를 활용하면 하나의 쿼리만으로 특정 레코드의 이전(previous) 레코드와 다음(next) 레코드를 동시에 조회할 수 있습니다. 게시글 상세 페이지에서 '이전 글 / 다음 글' 내비게이션을 구현할 때 특히 유용한 기법입니다.
기본 구문
두 개의 SELECT 문을 각각 다음 레코드와 이전 레코드를 조회하도록 작성한 뒤, UNION으로 결합하면 됩니다.
(SELECT * FROM yourTableName WHERE yourIdColumnName > yourValue ORDER BY yourIdColumnName ASC LIMIT 1)
UNION
(SELECT * FROM yourTableName WHERE yourIdColumnName < yourValue ORDER BY yourIdColumnName DESC LIMIT 1);
첫 번째 SELECT 문은 현재 값보다 큰 ID 중 가장 작은 값(즉, 다음 레코드)을 가져오고, 두 번째 SELECT 문은 현재 값보다 작은 ID 중 가장 큰 값(즉, 이전 레코드)을 가져옵니다. LIMIT 1을 지정했기 때문에 각각 한 건씩만 반환됩니다.
예제 테이블 생성
개념을 이해하기 위해 실습용 테이블을 먼저 만들어 보겠습니다.
mysql> CREATE TABLE previousAndNextRecordDemo
-> (
-> Id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> Name varchar(30)
-> );
Query OK, 0 rows affected (1.04 sec)
샘플 데이터 삽입
INSERT 명령으로 여러 개의 레코드를 추가합니다.
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('John');
Query OK, 1 row affected (0.17 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('Sam');
Query OK, 1 row affected (0.15 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('Carol');
Query OK, 1 row affected (0.14 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('Bob');
Query OK, 1 row affected (0.17 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('Larry');
Query OK, 1 row affected (0.20 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('David');
Query OK, 1 row affected (0.14 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('Ramit');
Query OK, 1 row affected (0.12 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('Maxwell');
Query OK, 1 row affected (0.15 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('Mike');
Query OK, 1 row affected (0.14 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('Robert');
Query OK, 1 row affected (0.19 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('Chris');
Query OK, 1 row affected (0.10 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('James');
Query OK, 1 row affected (0.16 sec)
mysql> INSERT INTO previousAndNextRecordDemo(Name) VALUES('Jace');
Query OK, 1 row affected (0.15 sec)저장된 전체 데이터 확인
SELECT 문으로 테이블의 모든 레코드를 조회합니다.
mysql> SELECT * FROM previousAndNextRecordDemo;
실행 결과는 다음과 같습니다.
+----+---------+
| Id | Name |
+----+---------+
| 1 | John |
| 2 | Sam |
| 3 | Carol |
| 4 | Bob |
| 5 | Larry |
| 6 | David |
| 7 | Ramit |
| 8 | Maxwell |
| 9 | Mike |
| 10 | Robert |
| 11 | Chris |
| 12 | James |
| 13 | Jace |
+----+---------+
13 rows in set (0.00 sec)
UNION으로 이전·다음 레코드 조회하기
이제 Id가 8인 레코드(Maxwell)를 기준으로, 이전 레코드와 다음 레코드를 단일 쿼리로 조회해 보겠습니다.
mysql> (SELECT * FROM previousAndNextRecordDemo WHERE Id > 8 ORDER BY Id ASC LIMIT 1)
-> UNION
-> (SELECT * FROM previousAndNextRecordDemo WHERE Id < 8 ORDER BY Id DESC LIMIT 1);
실행 결과는 다음과 같습니다.
+----+-------+
| Id | Name |
+----+-------+
| 9 | Mike |
| 7 | Ramit |
+----+-------+
2 rows in set (0.03 sec)
결과 해석
기준 레코드(Id = 8, Maxwell)를 제외하고, 바로 다음 순서인 Id 9(Mike)와 바로 이전 순서인 Id 7(Ramit)이 함께 반환된 것을 확인할 수 있습니다. 이처럼 UNION을 사용하면 별도의 서브쿼리나 여러 번의 쿼리 실행 없이, 단 한 번의 요청으로 이전·다음 레코드를 모두 얻을 수 있어 성능 면에서도 효율적입니다.