행 번호 차이 기법
ROW_NUMBER를 계열에서 빼 연속된 값을 아일랜드로 그룹화합니다.
행 번호 차이 기법은(는) CoddyKit의 무료 Coding Interview Prep 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Coding Interview Prep 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Coding Interview Prep 강의에는 총 4개의 강의가 포함되어 있습니다.
가장 우아한 구간 키
행 번호 차이 기법은 연속된 정수 또는 날짜로 이루어진 구간에서 면접관이 가장 보고 싶어 하는 기법입니다. 한 번의 뺄셈으로 그룹 키를 만들므로 LAG나 누적 합계가 필요하지 않습니다.
핵심 아이디어는 값 자체에서 ROW_NUMBER를 빼는 것입니다. 연속된 값의 어느 구간에서든 값과 행 번호는 매 단계 정확히 1씩 증가하므로, 두 값의 차이는 구간 전체에서 일정합니다. 이 일정한 값이 구간 키입니다.
차이가 일정하게 유지되는 이유
연속 구간에서 서로 인접한 두 행을 생각해 보십시오. 한 행에서 다음 행으로 이동하면 값이 1 증가하고 행 번호도 1 증가합니다. 두 값을 빼면 +1이 서로 상쇄되므로 value - row_number는 변하지 않습니다.
하지만 간격이 생기는 순간 값은 1보다 크게 뛰고, 행 번호는 여전히 1만큼만 증가합니다. 따라서 차이가 새로운 일정한 값으로 바뀝니다. 바로 이 변화가 한 구간과 다음 구간을 나눕니다.
데이터에 적용해 보기
로그인 날짜 1, 2, 3, 7, 8, 10을 다시 살펴보겠습니다. 행 번호와 차이를 나란히 놓으면 다음과 같습니다.
- 일수 1, 행 번호 1, 차이 0
- 일수 2, 행 번호 2, 차이 0
- 일수 3, 행 번호 3, 차이 0
- 일수 7, 행 번호 4, 차이 3
- 일수 8, 행 번호 5, 차이 3
- 일수 10, 행 번호 6, 차이 4
차이값(0,0,0,3,3,4)은 행을 세 구간으로 정확히 나눕니다. 차이가 같으면 같은 구간입니다.
SELECT
day_no,
ROW_NUMBER() OVER (ORDER BY day_no) AS rn,
day_no - ROW_NUMBER() OVER (ORDER BY day_no) AS grp
FROM logins
ORDER BY day_no;구간으로 합치기
차이를 그룹 키로 사용하면 최종 쿼리는 표준적인 통합 쿼리가 됩니다. 차이를 CTE로 감싼 다음 이를 기준으로 GROUP BY를 적용하십시오.
이 쿼리는 이전과 동일한 세 구간을 반환하지만, LAG와 누적 합계를 함께 사용하는 방식보다 SQL이 짧고 명확합니다. 정수 또는 일정한 간격으로 증가하는 순열에서는 이 방법을 가장 먼저 고려하십시오.
WITH keyed AS (
SELECT
day_no,
day_no - ROW_NUMBER() OVER (ORDER BY day_no) AS grp
FROM logins
)
SELECT
MIN(day_no) AS start_day,
MAX(day_no) AS end_day,
COUNT(*) AS length
FROM keyed
GROUP BY grp
ORDER BY start_day;주의할 점: 값은 1씩 증가해야 합니다
단순한 차이 기법은 수열이 매 단계마다 정확히 1씩 증가한다고 가정합니다. 이는 빈틈없는 정수와 연속된 달력 날짜에는 맞지만, 값이 다른 일정한 간격으로 증가하거나 중복값이 있으면 제대로 작동하지 않습니다.
- 2, 4, 6, 8과 같은 짝수는 값에서 행 번호를 뺀 결과를 사용하면 누락 구간처럼 보입니다.
- 중복값이 있으면 값은 그대로인데 행 번호만 계속 증가하므로 정렬이 어긋납니다.
이러한 한계와 이를 수정하는 방법을 알아야 암기한 요령을 넘어 실제로 이해했다고 할 수 있습니다.
일정한 간격 수열 수정하기
값이 1이 아니라 알려진 상수 k만큼씩 증가한다면 먼저 정규화해야 합니다. 값을 k로 나누거나 정수에는 value / k를 사용하여 각 단계가 다시 1씩 증가하도록 만든 다음 행 번호를 뺍니다.
예를 들어 2씩 증가하는 짝수에는 day_no / 2 - ROW_NUMBER()를 사용합니다. 이제 정규화된 값은 연속된 각 항목에서 1씩 증가하므로, 일정한 차이라는 특성이 다시 성립합니다.
SELECT
val,
(val / 2) - ROW_NUMBER() OVER (ORDER BY val) AS grp
FROM even_series
ORDER BY val;날짜에 적용하기
날짜는 이 기법이 실제로 가장 자주 적용되는 대상입니다. 달력 날짜는 행 번호에서 직접 뺄 수 없으므로 먼저 날짜를 일수로 변환해야 합니다. Postgres에서는 고정된 기준 날짜를 빼서 정수로 된 일수를 얻은 다음 같은 기법을 적용합니다.
연속된 달력 날짜의 차이는 1이므로, 일수와 행 번호의 차이는 연속 구간 안에서 다시 일정해집니다.
WITH keyed AS (
SELECT
login_date,
(login_date - DATE '2000-01-01')
- ROW_NUMBER() OVER (ORDER BY login_date) AS grp
FROM daily_logins
)
SELECT MIN(login_date) AS start_date,
MAX(login_date) AS end_date,
COUNT(*) AS days_in_run
FROM keyed GROUP BY grp ORDER BY start_date;데이터베이스별 날짜 차이 계산
날짜를 정수로 변환하는 단계는 데이터베이스 엔진마다 다르므로, 여러 데이터베이스 방언을 알고 있으면 면접에서 좋은 평가를 받을 수 있습니다.
- 포스트그레스: 날짜 리터럴을 뺍니다.
login_date - DATE '2000-01-01'은 정수를 반환합니다. - MySQL:
DATEDIFF(login_date, '2000-01-01')을 사용합니다. - 에스큐엘 서버:
DATEDIFF(day, '2000-01-01', login_date)를 사용합니다.
일부 엔진에서는 더 간결한 방법도 있습니다. 날짜에서 ROW_NUMBER일을 INTERVAL 연산으로 직접 뺀 다음, 그 결과인 기준 날짜로 GROUP BY하면 됩니다.
SELECT
login_date,
login_date - (ROW_NUMBER() OVER (ORDER BY login_date)
* INTERVAL '1 day') AS grp_date
FROM daily_logins;그룹별 PARTITION 추가하기
사용자별 연속 구간을 구하려면 그룹 열을 기준으로 행 번호를 PARTITION해야 합니다. 중요한 점은 그룹 키에 PARTITION 열도 포함해야 한다는 것입니다. 서로 다른 사용자가 우연히 같은 차이값을 만들 수 있기 때문입니다.
따라서 user_id와 계산된 차이값을 모두 GROUP BY해야 합니다. 최종 GROUP BY에서 user_id를 빠뜨리는 것은 면접관이 자주 찾아내는 미묘한 버그입니다.
WITH keyed AS (
SELECT user_id, day_no,
day_no - ROW_NUMBER()
OVER (PARTITION BY user_id ORDER BY day_no) AS grp
FROM logins
)
SELECT user_id, MIN(day_no) AS start_day,
MAX(day_no) AS end_day, COUNT(*) AS len
FROM keyed
GROUP BY user_id, grp
ORDER BY user_id, start_day;차이 기법과 LAG: 무엇을 사용할까요
이제 두 가지 확실한 기법을 사용할 수 있습니다. 상황에 맞게 선택하십시오.
- 행 번호 차이: 일정한 간격으로 증가하는 값의 연속 구간, 즉 빈틈없는 정수나 연속된 날짜를 다룰 때 가장 짧고 깔끔합니다. 인접함을 ‘일정한 값만큼 차이 나는 것’으로 정의할 때 첫 번째로 고려할 방법입니다.
- LAG와 누적합: 인접함이 일정한 숫자 간격이 아닐 때 더 유연합니다. 예를 들어 ‘이전 행과 같은 상태’나 불규칙한 사용자 지정 규칙을 다룰 때 적합합니다.
면접에서는 어떤 방법을 선택했는지와 그 이유를 설명하십시오. 문법보다 그 이유가 더 깊은 이해를 보여 줍니다.
중복에 대비해 안전하게 처리하기
값이 반복될 수 있는데도 연속된 각 구간마다 하나의 아일랜드를 만들고 싶다면, 먼저 DISTINCT나 그룹화 단계로 중복을 제거하여 행 번호와 값이 일대일로 대응하도록 하십시오. 또는 ROW_NUMBER 대신 DENSE_RANK를 사용하여 같은 값을 같은 순위로 처리할 수도 있습니다.
항상 면접관에게 중복이 발생할 수 있는지 물어보십시오. 중복값이 연속 구간을 늘려야 하는지, 아니면 구간 안에서 무시해야 하는지에 따라 적절한 대응이 달라집니다.
WITH d AS (SELECT DISTINCT day_no FROM logins)
SELECT day_no,
day_no - ROW_NUMBER() OVER (ORDER BY day_no) AS grp
FROM d;빠른 확인
이 기법이 왜 작동하는지 확실히 이해했는지 확인하십시오.
복습: 차이 기법
이제 가장 깔끔한 연속 구간 키를 익혔습니다.
- 핵심 공식:
value - ROW_NUMBER() OVER (ORDER BY value)는 연속된 각 구간에서 일정합니다. - 그 차이값으로 GROUP BY하여 시작값, 끝값, 길이를 구합니다.
- 일정한 간격 수열에서는 먼저 정규화합니다. 즉, 증가 간격으로 나눕니다.
- 날짜에서는 해당 데이터베이스 방언의 차이 함수를 사용하여 정수 일수로 변환합니다.
- 그룹별로 처리할 때는 행 번호를
PARTITION BY하고 최종GROUP BY에 그룹 열을 포함합니다. DISTINCT나DENSE_RANK로 중복에 대비합니다.
다음에는 연속 구간에서 빈 공간으로 초점을 옮겨 누락 구간을 찾아보겠습니다.
AI 튜터와 함께 Coding Interview Prep을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 90
- 레슨
- 360
자주 묻는 질문
“행 번호 차이 기법” 강의는 무료인가요?
네 — “행 번호 차이 기법” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Coding Interview Prep 강의 전체를 잠금 해제할 수 있습니다. Coding Interview Prep 강의에는 총 4개의 강의가 포함되어 있습니다.
“행 번호 차이 기법”에서 뭘 배우나요?
ROW_NUMBER를 계열에서 빼 연속된 값을 아일랜드로 그룹화합니다. 브라우저에서 직접 실행하는 실습 코드로 Coding Interview Prep을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Coding Interview Prep을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Coding Interview Prep은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“행 번호 차이 기법” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Coding Interview Prep 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Coding Interview Prep 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.