sql, lateral을 사용하여 직관적인 쿼리를 작성해보자.
lateral
- 요구사항이 복잡한 통계를 요구하는 경우, with를 사용하거나 혹은 2-3 중의 서브쿼리와 함께 복잡한 조건절을 필요로 한다. 이런 경우 상황에 따라 lateral이 문제 해결에 도움이 될 수 있다.
- 아래는 school 테이블과 students 테이블이 있다. 요구 사항으로는 학교 별로 1,2,3등을 출력하고 그 순서로 나열하는 것이다.
- lateral을 몰랐던 나는 아래와 같이 rank 함수와 join을 사용하여 쿼리를 작성할 것 같다.
create table school (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE students (
id INTEGER PRIMARY KEY,
sid INTEGER,
name TEXT NOT NULL,
gender TEXT NOT NULL,
score int
);
INSERT INTO school (id, name) values (1, '부산초'), (2, '서울초');
INSERT INTO students(id, sid, name, gender, score) VALUES
(1, 1, 'Ryan', 'M', 60)
, (2, 1, 'Jane', 'F', 70)
, (3, 1, 'Kinda', 'F', 95)
, (4, 1, 'Brown', 'M', 50)
, (5, 2, '진혁', 'M', 60)
, (6, 2, '영준', 'M', 90)
, (7, 2, '아영', 'F', 40)
, (8, 2, '하나', 'F', 80);
;
select sc.name, tb.name, tb.score
from (
select st.sid
, st.score
, rank() over(partition by st.sid order by st.score desc) rk
, st.name
from students st
) tb
join school sc on sc.id = tb.sid
where tb.rk < 4
order by tb.sid asc, tb.rk asc;
;
name | name | score |
---|---|---|
부산초 | Kinda | 95 |
부산초 | Jane | 70 |
부산초 | Ryan | 60 |
서울초 | 영준 | 90 |
서울초 | 하나 | 80 |
서울초 | 진혁 | 60 |
- lateral을 사용하면 다음과 같이 좀 더 직관적인 쿼리를 작성할 수 있다. students의 로직이 외부에 노출되지 않고 lateral 서브쿼리 내부에서 온전하게 표현된다.
- 이러한 쿼리를 작성할 수 있는 이유는, lateral 쿼리가 메인 쿼리의 FROM에 있는 테이블 school sc를 참조할 수 있기 때문이다.
SELECT sc.name, tb.name, tb.score
FROM school sc,
LATERAL ( -- INNER JOIN LATERAL로 바꿀 수 있다.
SELECT st.sid,
st.score,
st.name
FROM students st
WHERE sc.id = st.sid
order by st.score desc
LIMIT 3
) AS tb;