1. Faro

Nivel 10 · Desafío final: revisión de calidad de datos

La solicitud

De Kevin Brooks, Gerente de Operaciones

“Finanzas cierra el año pronto y quiero que primero limpiemos nuestros datos. Necesito tres listas: productos activos sin costo, líneas de pedido con cantidades imposibles y pedidos de 2025 que siguen pendientes en web o app.”

Tu objetivo

Paso 1 de 3. Desde products, devuelve product_id, name y category de los productos activos (is_active es verdadero) cuyo unit_cost es NULL.

  • Lee de la tabla productspendiente
  • Muestra exactamente product_id name categorypendiente
  • 8 filaspendiente

Paso 1 · tu consulta

SQL

Cargando el editor…

    ResultadoVista previa de products · presiona Ejecutar para ver el tuyo
    Vista previa de products
    product_idnamecategorysubcategoryunit_price
    101Vale Velvet LoveseatFurnitureSofas1659.00
    102Alder Oak Coffee TableFurnitureTables919.00
    103Orchard Rattan Dining ChairFurnitureChairs789.00
    104Upland Oak BookcaseFurnitureStorage429.00

    Mote revisa tu resultado

    Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.

    Paso 2 · tu consulta

    SQL

    Cargando el editor…

      ResultadoVista previa de order_items · presiona Ejecutar para ver el tuyo
      Vista previa de order_items
      order_item_idorder_idproduct_idquantityunit_price
      11001121931.99
      21001154311.99
      31002154411.99
      410021941149.00

      Mote revisa tu resultado

      Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.

      Paso 3 · tu consulta

      SQL

      Cargando el editor…

        ResultadoVista previa de orders · presiona Ejecutar para ver el tuyo
        Vista previa de orders
        order_idcustomer_idorder_datestatuschannel
        10011252023-01-01 20:51:19completedweb
        10021562023-01-02 07:58:46completedweb
        1003222023-01-02 10:25:27completedmarketplace
        1004482023-01-02 11:21:51completedmarketplace

        Mote revisa tu resultado

        Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.

        Tablas

        Datos de la tienda Harbor & Pine, listos para consultar.

        products120 filas · 8 columnas
        • product_idinteger
        • namevarchar
        • categoryvarchar
        • subcategoryvarchar
        • unit_pricedecimal
        • unit_costdecimal
        • launched_ondate
        • is_activeboolean
        Primeras 5 filas de products
        product_idnamecategorysubcategoryunit_priceunit_costlaunched_onis_active
        101Vale Velvet LoveseatFurnitureSofas1659.00NULL2023-09-11true
        102Alder Oak Coffee TableFurnitureTables919.00503.502024-05-16true
        103Orchard Rattan Dining ChairFurnitureChairs789.00429.872023-05-27true
        104Upland Oak BookcaseFurnitureStorage429.00214.702022-12-20true
        105Avery Leather Bed FrameFurnitureBeds449.00232.702021-08-31true
        order_items30,338 filas · 6 columnas
        • order_item_idinteger
        • order_idinteger
        • product_idinteger
        • quantityinteger
        • unit_pricedecimal
        • discount_pctdecimal
        Primeras 5 filas de order_items
        order_item_idorder_idproduct_idquantityunit_pricediscount_pct
        11001121931.990.00
        21001154311.990.00
        31002154411.990.00
        410021941149.000.00
        51002193219.990.00
        orders12,000 filas · 7 columnas
        • order_idinteger
        • customer_idinteger
        • order_datetimestamp
        • statusvarchar
        • channelvarchar
        • shipping_feedecimal
        • coupon_codevarchar
        Primeras 5 filas de orders
        order_idcustomer_idorder_datestatuschannelshipping_feecoupon_code
        10011252023-01-01 20:51:19completedweb0.00NULL
        10021562023-01-02 07:58:46completedweb0.00NULL
        1003222023-01-02 10:25:27completedmarketplace4.99WELCOME10
        1004482023-01-02 11:21:51completedmarketplace4.99WELCOME10
        1005822023-01-02 11:43:36completedweb0.00WELCOME10
        customers2,018 filas · 9 columnas
        • customer_idinteger
        • first_namevarchar
        • last_namevarchar
        • emailvarchar
        • cityvarchar
        • statevarchar
        • signup_datedate
        • segmentvarchar
        • referral_sourcevarchar
        Primeras 5 filas de customers
        customer_idfirst_namelast_nameemailcitystatesignup_datesegmentreferral_source
        1OwenHudsonowen.hudson@icloud.comSan FranciscoCA2022-06-02consumersearch
        2DouglasMendozadmendoza69@gmail.comAtlantaGA2022-06-02consumerNULL
        3HenryBrookshbrooks@lakesidecafe.comLos AngelesCA2022-06-04businessNULL
        4BrianGrahambgraham@bluecedarhomes.comSeattleWA2022-06-06businesspinterest
        5KyleJimenezkjimenez27@yahoo.comIndianapolisIN2022-06-07consumerNULL
        returns1,673 filas · 5 columnas
        • return_idinteger
        • order_item_idinteger
        • returned_ondate
        • reasonvarchar
        • refund_amountdecimal
        Primeras 5 filas de returns
        return_idorder_item_idreturned_onreasonrefund_amount
        1142023-01-10damaged83.69
        2422023-01-10wrong_item19.99
        31052023-01-14wrong_item10.99
        4242023-01-16changed_mind26.99
        51262023-01-16late20.99
        employees60 filas · 8 columnas
        • employee_idinteger
        • first_namevarchar
        • last_namevarchar
        • departmentvarchar
        • titlevarchar
        • manager_idinteger
        • hire_datedate
        • salaryinteger
        Primeras 5 filas de employees
        employee_idfirst_namelast_namedepartmenttitlemanager_idhire_datesalary
        1CatherineHaleExecutiveChief Executive OfficerNULL2016-03-01285000
        2RobertKimExecutiveChief Operating Officer12017-01-09235000
        3MeganCollinsSalesHead of Sales12018-04-16172000
        4ChloeGutierrezSalesAccount Executive32020-01-2172000
        5FrankBellSalesAccount Executive32023-05-2173000
        web_sessions40,000 filas · 7 columnas
        • session_idinteger
        • customer_idinteger
        • started_attimestamp
        • devicevarchar
        • sourcevarchar
        • pages_viewedinteger
        • convertedboolean
        Primeras 5 filas de web_sessions
        session_idcustomer_idstarted_atdevicesourcepages_viewedconverted
        1NULL2023-01-01 23:02:24mobilepaid1false
        2182023-01-01 15:07:49desktoppaid1false
        3NULL2023-01-01 16:55:46desktopdirect7false
        4NULL2023-01-01 12:43:28mobileorganic3false
        5NULL2023-01-01 13:06:21mobilesocial2false
        marketing_spend3,276 filas · 3 columnas
        • spend_datedate
        • channelvarchar
        • amountdecimal
        Primeras 5 filas de marketing_spend
        spend_datechannelamount
        2023-01-01paid492.99
        2023-01-01email37.38
        2023-01-01social200.53
        2023-01-02paid709.13
        2023-01-02email64.13

        La lección

        Las comprobaciones de calidad de datos son una gran parte de la semana de un analista, sobre todo antes de un cierre o de un informe para la junta. También son una excelente forma de practicar el filtrado, porque cada comprobación es solo una cláusula WHERE precisa.

        Paso 1: productos activos sin costo

        Un producto activo sin costo rompe todos los informes de margen. Dos condiciones, ambas obligatorias:

        WHERE is_active
          AND unit_cost IS NULL

        Los productos inactivos se excluyen a propósito: ya no se venden, así que Kevin no los necesita en la lista de limpieza. Recuerda del quiz que unit_cost = NULL no devolvería nada en silencio y haría que los datos parecieran más limpios de lo que son.

        Paso 2: cantidades imposibles

        Una línea vendida con cantidad 0 o menor es un error de datos: quizá una devolución registrada como venta negativa, quizá una transacción de prueba. WHERE quantity <= 0 encuentra tanto los valores cero como los negativos. En capítulos posteriores, cuando calcules los ingresos, excluirás estas filas con quantity > 0 y lo dirás en tus notas. Los analistas que las incluyen en silencio reportan ingresos que no cuadran con finanzas.

        Paso 3: pedidos pendientes en 2025

        Tres condiciones: status, un par de canales y un año. Los pedidos de marketplace los gestiona el socio del marketplace, así que Kevin solo quiere web y app.

        WHERE status = 'pending'
          AND channel IN ('web', 'app')
          AND order_date >= '2025-01-01'
          AND order_date <  '2026-01-01'

        Usar IN evita la trampa de la precedencia de AND/OR. Si escribieras channel = 'web' OR channel = 'app' sin paréntesis, los filtros de estado pendiente y de fecha solo se aplicarían a la mitad de app, y la lista incluiría todos los pedidos web hechos alguna vez.

        Por qué una revisión antes del cierre

        Cada una de estas listas alimenta una corrección distinta. Los costos faltantes van a merchandising, que es dueño de los precios de proveedores. Las cantidades imposibles van a ingeniería, porque algo en el checkout o en el proceso de importación las escribió. Los pedidos pendientes antiguos van a operaciones, que decide si enviar o cancelar. Dividir los resultados por responsable convierte un vago “los datos están desordenados” en tres tickets que de verdad se resuelven.

        Cómo reportar

        Cuando envíes resultados como estos, incluye el conteo y la regla que usaste, por ejemplo: “8 productos activos no tienen costo registrado (is_active = true y unit_cost IS NULL)”. Declarar la regla permite que quien lee detecte un malentendido antes de que alguien pase un día arreglando las filas equivocadas.

        Errores comunes

        • Comprobar un costo faltante con unit_cost = NULL. No devuelve nada y hace que los datos parezcan más limpios de lo que son. Usa unit_cost IS NULL.
        • Usar quantity < 0 para cantidades imposibles. Eso pierde las líneas con cantidad exactamente 0. Usa quantity <= 0.
        • Mezclar AND y OR sin paréntesis. status = 'pending' AND channel = 'web' OR channel = 'app' conserva todos los pedidos de app, sin importar su estado ni año. Usa channel IN ('web', 'app'), o envuelve el OR entre paréntesis.
        • Terminar el año con order_date <= '2025-12-31'. Si order_date tiene hora, los pedidos hechos después de la medianoche del 31 de diciembre quedan fuera. Usa order_date < '2026-01-01'.

        En SQL Server

        Los tres filtros se traducen directamente. Allí los booleanos son columnas BIT, así que el paso 1 se lee WHERE is_active = 1 AND unit_cost IS NULL. El año del paso 3 puede seguir siendo un rango semiabierto; YEAR(order_date) = 2025 da las mismas filas pero no puede usar un índice sobre la fecha.

        Elige qué puede ejecutarse en este sitio. Puedes cambiarlo cuando quieras desde "Configurar cookies", al pie de cada página.