문제 상황
프로젝트 진행 중 공용 프레임워크에 SQL Server 방언(dialect) 클래스를 추가해야 했습니다. 방언 클래스를 구현한 후 해당 메서드를 호출했을 때 다음과 같은 오류가 발생했습니다.
[오류] 스크립트 라인: 1-10 --------------------------------------
Id 1033, Level 15, State 1, Line 10
TOP 또는 FOR XML이 지정되지 않은 경우, ORDER BY 절은 뷰, 인라인 함수, 파생 테이블, 서브쿼리 및 공통 테이블 식에서 유효하지 않습니다.
메시지: 1033, 레벨: 15, 상태: 1, 프로시저: , 라인: 10
실행했던 SQL 문은 다음과 같습니다.
SELECT COUNT(*)
FROM (
SELECT wf.S_VER AS "S_VER"
FROM (
SELECT DISTINCT(S_VER)
FROM test
WHERE 1=1 AND I_COMMON = 1
) AS wf
ORDER BY wf.S_VER ASC
) a
환경
| 소프트웨어 | 버전 |
|---|---|
| SQL Server | 2008 |
오류 원인
오류 메시지를 보면 SQL 내부에 ORDER BY 키워드가 서브쿼리 안에서 사용되었기 때문입니다. SQL Server 엔진은 특정 컨텍스트(뷰, 파생 테이블, 서브쿼리 등)에서 ORDER BY를 허용하지 않으며, TOP 또는 FOR XML 절이 함께 명시되어야만 유효합니다.
해결 방법
TOP 키워드를 추가하여 이 문제를 우회할 수 있습니다. TOP을 사용하는 두 가지 방법이 있습니다.
1. 특정 개수 지정
구체적인 숫자로 상위 N개를 가져올 수 있으며, 이는 MySQL의 LIMIT과 유사합니다. 아래 예시는 테이블에서 20번째 이후의 10개 데이터를 가져옵니다.
SELECT TOP 10 *
FROM test2
WHERE id NOT IN (SELECT TOP 20 id FROM test2)
2. 특정 백분율 지정
전체 데이터가 필요하지만 정확한 개수를 모를 때는 백분율을 사용할 수 있습니다. 표현식은 TOP N PERCENT이며, N은 0에서 100 사이의 값이어야 합니다. 처음 문제가 된 SQL을 수정한 예는 다음과 같습니다.
SELECT COUNT(*)
FROM (
SELECT TOP 100 PERCENT wf.S_VER AS "S_VER"
FROM (
SELECT DISTINCT(S_VER)
FROM test
WHERE 1=1 AND I_COMMON = 1
) AS wf
ORDER BY wf.S_VER ASC
) a
실행 결과
수정 후 SQL 실행 결과는 다음과 같습니다.
[SQL] 스크립트 라인: 1-10 --------------------------------------
SELECT COUNT(*)
FROM (
SELECT TOP 100 PERCENT wf.S_VER AS "S_VER"
FROM (
SELECT DISTINCT(S_VER)
FROM test
WHERE 1=1 AND I_COMMON = 1
) AS wf
ORDER BY wf.S_VER ASC
) a
column1
----------
14
1개 행이 선택됨 [메타데이터 가져오기: 0ms] [데이터 가져오기: 0ms]
[실행 시각: 2020-06-09 13:35:03] [실행 시간: 4ms]
요약
이 문제는 SQL Server에서 ORDER BY가 서브쿼리와 같은 특정 컨텍스트에서 제한된다는 점을 보여줍니다. TOP 키워드를 적절히 활용하면 이 제약을 우회할 수 있으며, 특히 TOP 100 PERCENT는 모든 행을 정렬된 상태로 유지하면서 오류를 방지하는 실용적인 방법입니다.