중요 : MySQL 8 이상으로 업그레이드하고 정의되고 문서화 된 ROW_NUMBER () 함수를 사용하고 기능 제한 고대 버전의 MySQL에 연결된 오래된 해킹을 제거하십시오
이제 해킹 중 하나가 있습니다.
쿼리 내 변수를 주로 / 모두 사용하는 여기에 대한 답변은 설명서에서 다음과 같이 말한 사실을 무시하는 것 같습니다.
SELECT 목록의 항목을 위에서 아래로 순서대로 의존하지 마십시오. 하나의 SELECT 항목에 변수를 할당하지 않고 다른 항목에 사용하십시오.
따라서, 그들은 일반적으로 잘못하기 때문에 잘못된 답변을 얻을 수있는 위험이 있습니다
select
(row number variable that uses partition variable),
(assign partition variable)
이것들이 상향식으로 평가되면 행 번호가 작동을 멈 춥니 다 (파티션 없음)
따라서 보장 된 실행 순서로 무언가를 사용해야합니다. 다음 경우에 CASE를 입력하십시오.
SELECT
t.*,
@r := CASE
WHEN col = @prevcol THEN @r + 1
WHEN (@prevcol := col) = null THEN null
ELSE 1 END AS rn
FROM
t,
(SELECT @r := 0, @prevcol := null) x
ORDER BY col
개요 ld로서 prevcol의 할당 순서가 중요합니다. prevcol은 현재 행의 값을 할당하기 전에 현재 행의 값과 비교해야합니다 (그렇지 않으면 이전 행의 col 값이 아닌 현재 행 col 값이 됨). .
이것이 함께 맞는 방법은 다음과 같습니다.
첫 번째 WHEN이 평가됩니다. 이 행의 열이 이전 행의 열과 동일하면 @r이 증가하여 CASE에서 반환됩니다. 이 리턴 LED 값은 @r에 저장됩니다. 할당은 @r에 할당 된 값의 새로운 값을 결과 행으로 반환하는 MySQL의 기능입니다.
결과 세트의 첫 번째 행의 경우 @prevcol이 널 (서브 쿼리에서 널로 초기화 됨)이므로이 술어는 false입니다. 이 첫 번째 술어는 col이 변경 될 때마다 false를 리턴합니다 (현재 행이 이전 행과 다릅니다). 이로 인해 두 번째 WHEN이 평가됩니다.
두 번째 WHEN 술어는 항상 false이며 @prevcol에 새 값을 지정하는 것만으로 존재합니다. 이 행의 열이 이전 행의 열과 다르기 때문에 (이것이 동일하면 첫 번째 WHEN이 사용 되었기 때문에이를 알고 있음) 다음에 테스트 할 수 있도록 새 값을 할당해야합니다. 대입이 이루어진 후 대입 결과가 널과 비교되고 널과 동등한 것은 거짓이므로이 술어는 항상 거짓입니다. 그러나 적어도 평가하면이 행에서 col 값을 유지하는 작업을 수행 했으므로 다음 행의 col 값과 비교하여 평가할 수 있습니다
두 번째 WHEN이 false이므로 이는 (col)로 분할하는 열이 변경된 상황에서 @r에 새 값을 제공하고 번호 매기기를 1에서 다시 시작하는 것이 ELSE입니다.
우리는 이것이 다음과 같은 상황에 도달합니다.
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY pcol1, pcol2, ... pcolX ORDER BY ocol1, ocol2, ... ocolX) rn
FROM
t
일반적인 형태가 있습니다 :
SELECT
t.*,
@r := CASE
WHEN col1 = @pcol1 AND col2 = @pcol2 AND ... AND colX = @pcolX THEN @r + 1
WHEN (@pcol1 := pcol1) = null OR (@pcol2 := col2) = null OR ... OR (@pcolX := colX) = null THEN null
ELSE 1
END AS rn
FROM
t,
(SELECT @r := 0, @pcol1 := null, @pcol2 := null, ..., @pcolX := null) x
ORDER BY pcol1, pcol2, ..., pcolX, ocol1, ocol2, ..., ocolX
각주 :
pcol의 p는 "파티션"을 의미하고 ocol의 o는 "순서"를 의미합니다. 일반적인 형태에서는 변수 이름에서 "prev"를 삭제하여 시각적 혼란을 줄였습니다.
괄호 (@pcolX := colX) = null
가 중요합니다. 그것들이 없으면 @pcolX에 null을 할당하고 일이 중단됩니다.
이전 열을 비교하기 위해 결과 열을 파티션 열별로 정렬해야한다는 것은 타협입니다. 따라서 한 열에 따라 행 번호를 정렬 할 수 없지만 결과 집합을 다른 열에 정렬 할 수는 없습니다. 하위 쿼리를 사용 하여이 문제를 해결할 수는 있지만 문서는 LIMIT를 사용하지 않으면 하위 쿼리 순서가 무시 될 수 있다고 생각합니다. 공연
메소드가 작동하는지 테스트하는 것 이상으로 탐구하지는 않았지만 두 번째 WHEN의 술어가 최적화 될 위험이있는 경우 (null과 비교되는 것은 null / false이므로 할당을 실행하는 이유는 무엇입니까?) 또한 중지합니다. 이것은 내 경험에서 발생하지 않는 것 같지만 합리적으로 발생할 수 있다면 기꺼이 의견을 수락하고 해결책을 제안합니다.
@pcolX 변수를 생성하는 하위 쿼리에서 @pcolX를 생성하는 null을 실제 유형의 열로 캐스팅하는 것이 좋습니다. select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)
greatest-n-per-group
유사한 질문으로 안내하기 위해 태그가 지정 되었습니다.