소스: sql-src/mid_01_subquery/03_dialects.sql. 표준 문법으로는 DB마다 똑같이 동작하지만, 상위 N 조회와 인라인 뷰 별칭 표기는 방언 차이가 있습니다.
| 기능 | Oracle · Tibero | MySQL | MSSQL |
|---|---|---|---|
| 상위 N 행 | 인라인 뷰 + ROWNUM |
LIMIT n |
TOP n |
| 인라인 뷰 별칭 | 선택, AS 쓰면 오류 |
필수, AS 선택 |
필수, AS 선택 |
표준 문법인 OFFSET n ROWS FETCH NEXT m ROWS ONLY 는 Oracle 12c·MSSQL 2012 부터 됩니다. MySQL 은 이 문법이 없고 LIMIT 만 씁니다. 페이징 전체는 실무 01 에서 다룹니다.
-- 표준
SELECT
name
, (SELECT sal FROM emp WHERE dept = '개발') AS one_sal
FROM emp
WHERE dept = '개발';예상 오류: Scalar subquery contains more than one row개발 부서는 3명이라 서브쿼리가 3행을 반환합니다. 스칼라 서브쿼리는 1행만 허용하므로 오류가 납니다. 부서 조건을 빼먹고 전체를 서브쿼리에 넣었을 때 흔히 나는 실수입니다.
-- Oracle · Tibero
SET MODE Oracle;
SELECT
name
, sal
FROM (
SELECT
name
, sal
FROM emp
ORDER BY sal DESC
) t
WHERE ROWNUM <= 3;NAME | SAL
-------+----
김대표 | 900
이팀장 | 650
정팀장 | 600
(3행)ROWNUM 은 정렬 전 원본 순서에 매겨지므로, 정렬 결과에서 상위 N을 뽑으려면 먼저 인라인 뷰로 정렬을 끝내야 합니다. ORDER BY 없이 바로 WHERE ROWNUM <= 3 을 쓰면 정렬 안 된 임의의 3행이 나옵니다.
주의실제 Oracle 은 인라인 뷰 별칭 앞에
AS를 쓰면 문법 오류입니다(FROM (...) t는 되지만FROM (...) AS t는 안 됩니다). H2 는 이 제약을 검사하지 않고 두 표기를 모두 실행합니다. 그래서 이 오류는 H2 로 재현되지 않으며 문법 검토만 했습니다.
-- MySQL
SET MODE MySQL;
SELECT
t.dept
, t.avg_sal
FROM (
SELECT
dept
, AVG(sal) AS avg_sal
FROM emp
GROUP BY dept
) t
WHERE t.avg_sal > 400
ORDER BY t.avg_sal DESC;
SELECT
name
, sal
FROM emp
ORDER BY sal DESC
LIMIT 3;DEPT | AVG_SAL
-----+--------
경영 | 900.0
개발 | 500.0
지원 | 500.0
영업 | 440.0
인사 | 425.0
(5행)
NAME | SAL
-------+----
김대표 | 900
이팀장 | 650
정팀장 | 600
(3행)실제 MySQL 은 파생 테이블(FROM 절 서브쿼리)에 별칭이 없으면 오류를 냅니다. H2 는 별칭 없이도 통과시키므로 이 오류는 재현되지 않고 문법 검토만 했습니다. 예제는 항상 별칭을 붙인 형태로 실었습니다.
-- MSSQL
SET MODE MSSQLServer;
SELECT TOP 3
name
, sal
FROM emp
ORDER BY sal DESC;
SELECT
t.name
, t.sal
, t.dept_avg
FROM (
SELECT
name
, sal
, (SELECT AVG(sal) FROM emp x WHERE x.dept = e.dept) AS dept_avg
FROM emp e
) t
WHERE t.sal > t.dept_avg
ORDER BY t.dept_avg DESC;NAME | SAL
-------+----
김대표 | 900
이팀장 | 650
정팀장 | 600
(3행)
NAME | SAL | DEPT_AVG
-------+-----+---------
이팀장 | 650 | 500.0
정팀장 | 600 | 440.0
서팀장 | 550 | 425.0
(3행)TOP n 은 SELECT 바로 뒤에 붙는다는 점이 Oracle·MySQL 과 다릅니다. 두 번째 문장은 인라인 뷰 안에 상관 서브쿼리를 넣어 부서 평균보다 많이 받는 사람만 걸렀습니다. 서브쿼리 종류는 섞어 쓸 수 있습니다.
주의실제 MSSQL 에서 INT 컬럼의
AVG는 정수로 잘립니다. 위 425.0 은 425 가 됩니다. 소수점이 필요하면AVG(sal * 1.0)처럼 먼저 소수로 바꿉니다.