openlang

COUNT(col) 때문에 바뀐 비율의 뜻

어떤 보고서가 배송일이 있는 주문의 비율을 COUNT(shipped_at) * 1.0 / COUNT(*)로 보여 줬습니다. 한동안은 맞았습니다. 그러다 대기 중인 주문이 shipped_at이 NULL인 채로 같은 테이블에 들어오기 시작했고 비율이 떨어졌습니다. 쿼리는 하나도 바뀌지 않았습니다.

COUNT(*)는 입력 행을 셉니다. COUNT(shipped_at)는 그 값이 NULL이 아닌 행을 셉니다. 비율은 처음부터 "전체 행 중 날짜가 있는 행"이었고, 그 밑에서 행 집합이 바뀐 것입니다.

확인할 것이 세 가지 있고, 서로 같지 않습니다.

  1. 분모에 이름을 붙입니다. COUNT(*) FILTER (WHERE status <> 'pending')는 이 비율이 어떤 행에 대한 것인지 말해 줍니다.
  2. 나눗셈을 조심합니다. PostgreSQL에서 count는 bigint를 돌려주므로, COUNT(a) / COUNT(*)는 1보다 작은 비율을 전부 0으로 잘라 버립니다. * 1.0이 붙은 이유입니다.
  3. 그 열에서 NULL이 무슨 뜻인지 묻습니다. 아직 배송 전과 배송일 미상은 다른 사실이고, 개수로는 둘을 구별할 수 없습니다.

배송된 주문 둘, 대기 주문 둘만 있어도 두 계산이 눈에 띄게 갈립니다.

SELECT COUNT(shipped_at) * 1.0 / COUNT(*) AS naive,
       COUNT(shipped_at) * 1.0
         / COUNT(*) FILTER (WHERE status <> 'pending')
         AS shipped_share
FROM orders;
-- naive 0.5, shipped_share 1.0

R에도 이 갈림이 있습니다. length(x)는 NA 항목까지 세고 sum(!is.na(x))는 세지 않습니다. 보고서를 R로 만들 때 저는 비율 옆에 sum(is.na(x))를 함께 찍어서, 분자가 몇 행을 건너뛰었는지 읽는 사람이 볼 수 있게 합니다.

이어지는 대화 1

서로의 근거를 따라
  1. 고유 링크

    비율 옆에 COUNT(*) - COUNT(shipped_at)를 찍어 둔다. 그러면 이런 변화가 수수께끼가 아니라 숫자로 온다.

같은 질문의 다른 갈래

  1. 문자열로 온 count(*)와 121건

    할 일 목록 화면이에요. 상단에 총 12건이 떠 있고, 제가 할 일을 하나 추가해요. 서버 응답을 기다리지 않고 숫자부터 올리려고 total + 1을 했는데, 화면에 총 121건이 떴어요. (순간 할 일이 백 개 넘게 생긴…

  2. 에러 없이 끝난 rows.Next 루프

    database/sql로 만든 작은 도구가 목록을 반만 돌려줬어. 에러 없이. 코드는 이래. 컨텍스트에 데드라인이 있었어. 가져오는 도중에 데드라인이 지나서 rows.Next()가 false를 줬고, 루프가 끝났고, 함수는…

    답글 3sqlgo
  3. 기다린 뒤 WHERE를 다시 보는 UPDATE

    PostgreSQL Read Committed에서 두 세션이 있고, 잔액이 15인 계좌가 하나 있으며, 두 세션이 같은 문장을 실행합니다. 세션 A가 행을 갱신했고 아직 커밋하지 않았습니다. 세션 B는 그 행을 찾고, 갱신…

    답글 0sql