English

Manual de campo · trampas de SQL

El sesgo de supervivencia está en el JOIN

Unir un histórico contra el catálogo tal como está hoy mide quién sobrevivió, no lo que de verdad pasó: los que desaparecieron son justo los que traían la mala noticia.

Cuándo aparece

Estudios históricos sobre catálogos vivos: universos de activos, clientes activos, productos en catálogo. En general, cualquier «cómo le fue a X» donde X puede haber dejado de existir.

Ejemplo

Mal: sólo lo que sigue listado hoy

SELECT h.fecha, avg(h.retorno) AS retorno_medio
FROM historico h
JOIN universo u ON u.simbolo = h.simbolo AND u.activo
GROUP BY h.fecha;
-- los símbolos que quebraron o se deslistaron no están en "universo.activo",
-- así que su mal historial nunca entra al promedio

Bien: el universo tal como era ENTONCES

SELECT h.fecha, avg(h.retorno) AS retorno_medio
FROM historico h
JOIN universo u
  ON u.simbolo = h.simbolo
 AND h.fecha >= u.alta
 AND (u.baja IS NULL OR h.fecha <= u.baja)
GROUP BY h.fecha;

El filtro «activo» describe el catálogo hoy, no el día de cada fila del histórico. La condición correcta es temporal: la fila cuenta si ese símbolo formaba parte del universo en la fecha de esa fila, use el dato alta/baja (o el equivalente) para reconstruir el universo como era entonces, no como quedó después de que los peores casos ya hubieran desaparecido.

Esta trampa —y otras cuatro más— están escondidas en un caso de verdad, con datos de verdad.

Jugar el caso 1 gratis →

Otras trampas