2016-12-11 2 views
1

문제 : 여기COALESCE 함수는

CREATE TABLE Score(`id` int, `col1` INT NULL); 
INSERT INTO Score 
    (`id`, `col1`) 
VALUES 
    (2, NULL), 
    (3, 10), 
    (5, -1), 
    (7, NULL), 
    (11, NULL), 
    (13, -12), 
    (17, NULL), 
    (19, NULL), 
    (23, 1759); 
http://sqlmag.com/t-sql/last-non-null-puzzle을 발견, 번호 순서에 따라 테이블에서 마지막 비 NULL 값을 찾을 수 있습니다

원하는 출력 : SQLFiddle에서

id          col1        lastval 
----------- ----------- ----------- 
2           NULL        NULL 
3           10          10 
5           -1          -1 
7           NULL        -1 
11          NULL        -1 
13          -12         -12 
17          NULL        -12 
19          NULL        -12 
23          1759        1759 

내 코드 MySQL 5.6

SELECT s1.id, COALESCE(s2.col1) 
FROM score s1 JOIN score s2 
ON s1.id >= s2.id 
GROUP BY s1.id 
ORDER BY s1.id, s2.id DESC 

내가 이해하는대로 NULL이 아닌 첫 번째 값을 제공합니다. 목록. 그러나 모든 열에 대해 (null)을 제공합니다. COALESCE이 (가) 작동하지 않는 이유를 지적 할 수 있습니까? 또한 COALESCE을 제거하면 GROUP BY 절이 s2.col1 열의 첫 번째 값을 반환하기 때문에 질문에 대답해야한다는 것을 알게되었습니다. 나는 틀릴지도 모른다.

답변

2

COALESCE을하는 데 도움이 인수는 목록의 첫 번째 null이 아닌 값 을 반환 바랍니다. 그룹화 된 행 집합에 대해 COALESCE()를 같은 식에 적용하면 암시 적으로 동작하지 않습니다. SUM() 또는 GROUP_CONCAT()과 같은 집계 함수가 아닙니다.

하나의 인수 만 사용했기 때문에 하나의 인수로 사용하는 것은 의미가 없습니다. 따라서 QUALESCE() 호출 안에 넣지 않고 쿼리의 선택 목록에 s2.col1을 넣는 것과 정확히 같습니다.

그런 다음 GROUP BY 함수에서 그룹화되지 않은 열을 참조 할 때 MySQL의 기본 동작이 그대로 유지됩니다. MySQL은 임의로 그룹의 일부 행에서 s2.col1 값을 선택합니다. 실제로는 인덱스 순서로 읽는 그룹의 첫 번째 행이지만이 항목에 의존해서는 안됩니다.

예에서 조인은 모든 행 s1을 모든 행 s2에 결합하여 s2.id이 더 빠릅니다. 모든 그룹은 테이블의 첫 번째 행을 포함합니다. s2.id=2. 그리고 그 행은 col1에 대해 NULL을 갖는다.

해결하려는 SQL 퍼즐을 읽었습니다. MySQL은 윈도우 함수를 지원하지 않기 때문에 MySQL에서는 특히 어색하다.

이러한 경우의 해결책은 쿼리가 테이블의 행을 반복 할 때 값을 변경하는 MySQL User-Defined Variables을 사용하는 것입니다. 이것은 매우 까다로울 수 있습니다. 여기


내가 (어떤 MySQL의 사용자 변수) 휴대용 방법으로 문제를 해결할 방법은 다음과 같습니다

SELECT id, col1, @lastval := COALESCE(col1, @lastval) AS lastval 
FROM (SELECT @lastval := NULL) AS _init 
CROSS JOIN Score 
ORDER BY id; 
:

여기
SELECT s1.id, s1.col1, s2.col1 as lastval 
FROM Score AS s1 
LEFT OUTER JOIN Score AS s2 ON s2.id <= s1.id AND s2.col1 IS NOT NULL 
LEFT OUTER JOIN Score AS s3 ON s3.id > s2.id AND s3.id <= s1.id AND s3.col1 IS NOT NULL 
WHERE s3.id IS NULL 
ORDER BY s1.id; 

하나는 MySQL 사용자 변수를 사용하여 해결할 수있는 방법

상관 관계가있는 하위 쿼리를 사용하기 때문에 귀하가 아래에 귀하의 의견에 게시 한 쿼리를 피할 수 있습니다. 상관 관계가있는 하위 쿼리는 일반적으로 성능에 좋지 않습니다.

+0

SQL에서 사용자 정의 변수에 익숙하지 않습니다. 하지만 해결책을 찾았습니다. 당신은이 'SELECT s1.id를 작동하는 경우, (s2.id <= s1.id 및 s2.col1이 s2.id DESC LIMIT 1에 의해 NULL ORDER을지지 않습니다 점수 S2 로부터 s2.col1을 선택)을 확인할 수 있습니다 AS 값 FROM score s1 ORDER BY s1.id' –

+0

두 번째 쿼리는 MySQL 사용자 변수를 사용하여 설명 할 수 있습니까? –

0

나는 당신이 할 일이 무엇인지 알지 못했고 또한 mysql에서 작동 할 것이 확실치 않지만이 중 하나는 tsql에서 작동합니다. 나는()

SELECT s1.id, COALESCE(min(s2.col1),0) FROM score s1 
    JOIN score s2 ON s1.id >= s2.id GROUP BY s1.id 
    ORDER BY s1.id, min(s2.col1) DESC 
+0

[질문] (http://sqlmag.com/t-sql/last-non-null-puzzle)의 링크를 참조하십시오. 이 'COALESCE (min (s2.col1), 0)'을 한 이유와 이것이 어떻게 작동하는지 설명 할 수 있습니까? –

+0

출력이 원하는 것이 아닙니다. 더 명확하게 질문을 편집했습니다. –

+0

방법은 매개 변수가 아닌 연산 결과를 처리하기 위해 coalesce()를 사용합니다. 예를 들어 합계 (a)/합계 (b)가있는 경우 coalesce()를 사용하면 null을 처리 할 수 ​​있습니다. 다시 질문하고 내가 원하는 것을 이해하려고 노력하고 있습니다. –