# SQL Avanzado para Entrevistas de Analista de Datos: Subconsultas, Pivots y Optimizacion de Consultas en 2026 > Domina los temas de SQL avanzado que aparecen en entrevistas tecnicas para analistas de datos en 2026. Subconsultas correlacionadas, pivots con agregacion condicional, planes EXPLAIN y estrategias de indexacion en PostgreSQL. - Published: 2026-05-15 - Updated: 2026-05-15 - Author: Anthony Fillion-Maillet - Tags: sql, data-analytics, interview, query-optimization, subqueries - Reading time: 10 min --- El mercado laboral para analistas de datos en America Latina experimenta una competencia cada vez mas intensa. Empresas de tecnologia, fintechs y corporaciones con equipos de datos maduros han elevado la barra tecnica de sus procesos de seleccion, y las evaluaciones de SQL dejaron de limitarse a consultas basicas con SELECT y GROUP BY. En 2026, los candidatos enfrentan ejercicios que exigen dominio de subconsultas correlacionadas, transformaciones pivot mediante agregacion condicional y capacidad para diagnosticar consultas lentas utilizando planes de ejecucion. Este articulo desglosa cada uno de esos temas con ejemplos ejecutables sobre PostgreSQL 17, orientados a resolver los problemas exactos que plantean los entrevistadores. > **Que evaluan realmente los entrevistadores en SQL** > > Las evaluaciones tecnicas de SQL para roles de data analyst en 2026 giran alrededor de tres ejes fundamentales: capacidad para descomponer logica compleja mediante subconsultas y CTEs bien estructurados, habilidad para transformar datos almacenados en filas hacia reportes de formato columnar con agregacion condicional, y conocimiento practico de rendimiento a traves de planes EXPLAIN e indexacion. La optimizacion es el area donde falla la mayoria de los candidatos, lo que convierte ese conocimiento en un diferenciador importante. ## Subconsultas Correlacionadas vs. Subconsultas Regulares Comprender la diferencia entre una subconsulta regular y una correlacionada resulta esencial para cualquier entrevista de SQL a nivel intermedio o avanzado. Una subconsulta regular se ejecuta una unica vez y produce un resultado fijo que la consulta externa utiliza como referencia. Una subconsulta correlacionada, en cambio, hace referencia a columnas de la consulta externa, lo que obliga al motor de base de datos a recalcularla para cada fila del conjunto de resultados principal. El caso mas sencillo de subconsulta regular es la comparacion contra un umbral global. La consulta interna calcula un valor escalar una sola vez, y la consulta externa filtra las filas que superan ese valor. ```sql -- regular_subquery_threshold.sql -- Find all orders above the average order value SELECT order_id, customer_id, total_amount FROM orders WHERE total_amount > ( -- Executes once, returns a single scalar value SELECT AVG(total_amount) FROM orders ); ``` La situacion cambia cuando la comparacion depende del contexto de cada fila. El ejemplo clasico en entrevistas consiste en identificar empleados cuyo salario supera el promedio de su propio departamento. Aqui la subconsulta necesita acceder al departamento de la fila actual, generando una dependencia que fuerza la reevaluacion en cada iteracion. ```sql -- correlated_subquery_department.sql -- Employees earning above their department average SELECT e.employee_id, e.name, e.department, e.salary FROM employees e WHERE e.salary > ( -- Re-evaluated for each employee's department SELECT AVG(e2.salary) FROM employees e2 WHERE e2.department = e.department ); ``` Esta version correlacionada recalcula el promedio salarial por departamento para cada empleado. Sobre tablas con miles o millones de registros, el costo se vuelve prohibitivo. La alternativa optimizada consiste en precalcular los promedios departamentales en un CTE y unirlos mediante JOIN, logrando el mismo resultado con una sola pasada sobre los datos. ```sql -- optimized_with_cte.sql -- Same result, single pass over the data WITH dept_avg AS ( SELECT department, AVG(salary) AS avg_salary FROM employees GROUP BY department ) SELECT e.employee_id, e.name, e.department, e.salary FROM employees e JOIN dept_avg d ON e.department = d.department WHERE e.salary > d.avg_salary; ``` Durante una entrevista, el enfoque ganador consiste en escribir primero la version correlacionada para demostrar comprension conceptual, y luego refactorizarla al CTE explicando la mejora de rendimiento. Los entrevistadores valoran esa capacidad de analisis critico sobre el propio codigo. ## Patrones de Subconsultas que Aparecen en Entrevistas de Data Analyst Existen tres patrones de subconsultas que se repiten con alta frecuencia en las evaluaciones tecnicas: verificaciones de pertenencia con EXISTS, subconsultas escalares dentro de la clausula SELECT y tablas derivadas en la clausula FROM. **EXISTS vs. IN** -- La diferencia de rendimiento entre ambos operadores se manifiesta en conjuntos de datos grandes. EXISTS detiene la busqueda en cuanto encuentra la primera coincidencia, mientras que IN necesita materializar el resultado completo de la subconsulta antes de iniciar la comparacion. ```sql -- exists_vs_in.sql -- Customers who placed at least one order in 2026 (EXISTS — preferred) SELECT c.customer_id, c.name FROM customers c WHERE EXISTS ( SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id AND o.order_date >= '2026-01-01' ); -- Equivalent with IN (slower on large datasets) SELECT customer_id, name FROM customers WHERE customer_id IN ( SELECT customer_id FROM orders WHERE order_date >= '2026-01-01' ); ``` **Subconsulta escalar en SELECT** -- Resulta util cuando se necesita agregar una columna calculada sin realizar un JOIN completo contra otra tabla o agregacion. El siguiente ejemplo obtiene, para cada producto, el ingreso total de su categoria. ```sql -- scalar_subquery_select.sql -- Each product with its category's total revenue SELECT p.product_id, p.product_name, p.category, ( SELECT SUM(oi.quantity * oi.unit_price) FROM order_items oi JOIN products p2 ON oi.product_id = p2.product_id WHERE p2.category = p.category ) AS category_total_revenue FROM products p; ``` Este patron mantiene la legibilidad cuando se agregan una o dos columnas. Si la cantidad de columnas calculadas crece, conviene migrar a un CTE con JOIN para mejorar tanto la claridad como el rendimiento de la consulta. ## Consultas Pivot con Agregacion Condicional Las consultas pivot constituyen uno de los temas mas recurrentes en entrevistas para analistas de datos porque reflejan una necesidad real del dia a dia: transformar datos almacenados en formato de filas hacia reportes con formato columnar. Aunque algunos motores de base de datos ofrecen un operador PIVOT nativo, la tecnica portable y universalmente aceptada en entrevistas utiliza sentencias CASE dentro de funciones de agregacion. El siguiente ejemplo transforma los ingresos mensuales por producto en un formato donde cada mes ocupa su propia columna. ```sql -- pivot_monthly_revenue.sql -- Monthly revenue pivot: one row per product, one column per month SELECT product_id, product_name, SUM(CASE WHEN EXTRACT(MONTH FROM order_date) = 1 THEN quantity * unit_price ELSE 0 END) AS jan_revenue, SUM(CASE WHEN EXTRACT(MONTH FROM order_date) = 2 THEN quantity * unit_price ELSE 0 END) AS feb_revenue, SUM(CASE WHEN EXTRACT(MONTH FROM order_date) = 3 THEN quantity * unit_price ELSE 0 END) AS mar_revenue, SUM(CASE WHEN EXTRACT(MONTH FROM order_date) = 4 THEN quantity * unit_price ELSE 0 END) AS apr_revenue, -- Repeat for remaining months SUM(quantity * unit_price) AS total_revenue FROM order_items oi JOIN orders o ON oi.order_id = o.order_id JOIN products p ON oi.product_id = p.product_id WHERE o.order_date >= '2026-01-01' GROUP BY product_id, product_name ORDER BY total_revenue DESC; ``` La misma tecnica de agregacion condicional se extiende a pivots multidimensionales. El ejemplo a continuacion segmenta las sesiones de usuario por tipo de dispositivo y calcula el porcentaje de sesiones moviles, un analisis habitual en equipos de producto. ```sql -- pivot_user_activity.sql -- User activity: sessions by day of week and device type SELECT user_id, COUNT(CASE WHEN device_type = 'mobile' THEN 1 END) AS mobile_sessions, COUNT(CASE WHEN device_type = 'desktop' THEN 1 END) AS desktop_sessions, COUNT(CASE WHEN device_type = 'tablet' THEN 1 END) AS tablet_sessions, ROUND( COUNT(CASE WHEN device_type = 'mobile' THEN 1 END) * 100.0 / COUNT(*), 1 ) AS mobile_pct FROM user_sessions WHERE session_date >= CURRENT_DATE - INTERVAL '30 days' GROUP BY user_id HAVING COUNT(*) >= 5 -- Only users with meaningful activity ORDER BY mobile_pct DESC; ``` El uso de HAVING para filtrar usuarios con actividad significativa es un detalle que demuestra madurez analitica. Los entrevistadores prestan atencion a estos filtros porque reflejan la capacidad de producir reportes limpios y accionables. ## Pivot Dinamico con CROSSTAB en PostgreSQL Cuando las categorias del pivot no se conocen de antemano o pueden variar con el tiempo, PostgreSQL ofrece la funcion CROSSTAB a traves de la extension `tablefunc`. Este enfoque resulta especialmente util para reportes trimestrales o dashboards donde las dimensiones cambian segun el periodo analizado. ```sql -- crosstab_dynamic_pivot.sql -- Enable the extension (once per database) CREATE EXTENSION IF NOT EXISTS tablefunc; -- Revenue by product and quarter using CROSSTAB SELECT * FROM crosstab( $$ SELECT product_name, 'Q' || EXTRACT(QUARTER FROM order_date)::TEXT AS quarter, SUM(quantity * unit_price) AS revenue FROM order_items oi JOIN orders o ON oi.order_id = o.order_id JOIN products p ON oi.product_id = p.product_id WHERE EXTRACT(YEAR FROM o.order_date) = 2026 GROUP BY product_name, quarter ORDER BY product_name, quarter $$, $$ VALUES ('Q1'), ('Q2'), ('Q3'), ('Q4') $$ ) AS pivot_table( product_name TEXT, q1_revenue NUMERIC, q2_revenue NUMERIC, q3_revenue NUMERIC, q4_revenue NUMERIC ); ``` Aunque CROSSTAB es especifico de PostgreSQL y no se encuentra disponible en todos los motores, conocer esta herramienta demuestra familiaridad con el ecosistema de extensiones de PostgreSQL, algo valorado positivamente en empresas que utilizan este motor como base de datos principal. ## Optimizacion de Consultas SQL: Planes EXPLAIN y Analisis de Rendimiento Las preguntas sobre optimizacion de consultas representan el area donde mas candidatos tropiezan durante las entrevistas. Saber escribir una consulta correcta no es suficiente; los entrevistadores esperan que el candidato pueda diagnosticar por que una consulta es lenta y proponer soluciones concretas. La herramienta fundamental para este diagnostico es EXPLAIN ANALYZE, que ejecuta la consulta y muestra el plan de ejecucion real junto con metricas de tiempo y uso de buffers. ```sql -- explain_analyze_example.sql -- Analyze a slow query to identify bottlenecks EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) SELECT c.customer_id, c.name, COUNT(o.order_id) AS order_count, SUM(o.total_amount) AS lifetime_value FROM customers c JOIN orders o ON c.customer_id = o.customer_id WHERE o.order_date >= '2025-01-01' GROUP BY c.customer_id, c.name HAVING SUM(o.total_amount) > 1000 ORDER BY lifetime_value DESC; ``` Al interpretar la salida de EXPLAIN, los elementos clave a identificar son los siguientes: la presencia de Seq Scan (escaneo secuencial) en tablas grandes indica la ausencia de un indice adecuado; Index Scan confirma que el planificador esta utilizando un indice; el tipo de join (Nested Loop, Hash Join o Merge Join) revela la estrategia del optimizador; y la diferencia entre las filas estimadas y las filas reales senala si las estadisticas de la tabla estan desactualizadas. Un desfase significativo entre estimaciones y valores reales se corrige ejecutando ANALYZE sobre las tablas involucradas. Durante una entrevista, no se espera que el candidato memorice cada operador del plan. Lo importante es demostrar un enfoque sistematico: identificar el nodo mas costoso, verificar si hay escaneos secuenciales evitables y proponer indices o reescrituras que mejoren el rendimiento. ## Estrategias de Indexacion para Entrevistas SQL La indexacion es la palanca mas directa para mejorar el rendimiento de consultas, y los entrevistadores esperan que los candidatos conozcan mas alla de los indices simples. Los indices compuestos, de cobertura y parciales forman parte del repertorio que distingue a un analista capaz de resolver problemas de performance en contextos reales. Un indice simple acelera las consultas que filtran por una sola columna. Un indice compuesto cubre multiples columnas de filtrado y resulta eficaz cuando el orden de las columnas en el indice coincide con los patrones de filtro de las consultas mas frecuentes. ```sql -- indexing_strategies.sql -- Index on order_date: filters a small percentage of rows CREATE INDEX idx_orders_date ON orders (order_date); -- Composite index for queries filtering on both columns CREATE INDEX idx_orders_customer_date ON orders (customer_id, order_date); -- Covering index: includes columns needed in SELECT -- Enables Index Only Scan (no table access) CREATE INDEX idx_orders_covering ON orders (customer_id, order_date) INCLUDE (total_amount, status); ``` El indice compuesto `idx_orders_customer_date` respeta la regla del prefijo mas a la izquierda: es utilizable para consultas que filtran por `customer_id` solo, o por `customer_id` y `order_date` juntos, pero no para consultas que filtran exclusivamente por `order_date`. El indice de cobertura con la clausula INCLUDE agrega las columnas `total_amount` y `status` a las hojas del indice, permitiendo resolver la consulta directamente desde el indice sin acceder a la tabla (Index Only Scan). Los indices parciales representan una herramienta avanzada que reduce el tamano del indice al cubrir unicamente un subconjunto de filas que cumple una condicion especifica. ```sql -- partial_index.sql -- Only index active orders (smaller, faster index) CREATE INDEX idx_orders_active ON orders (customer_id, order_date) WHERE status = 'active'; -- Only index recent data for dashboard queries CREATE INDEX idx_orders_recent ON orders (order_date) WHERE order_date >= '2026-01-01'; ``` El indice parcial `idx_orders_active` resulta particularmente eficiente cuando la gran mayoria de las ordenes estan archivadas o canceladas y las consultas operan casi exclusivamente sobre ordenes activas. El planificador de PostgreSQL utiliza este indice unicamente cuando la clausula WHERE de la consulta coincide con la condicion del indice. > **Anti-patrones de indexacion que se deben evitar** > > Crear un indice por cada columna no constituye una estrategia valida de optimizacion. Cada indice adicional ralentiza las operaciones de escritura (INSERT, UPDATE y DELETE). Una tabla con mas de 10 indices bajo cargas de escritura intensiva experimenta una degradacion notable del rendimiento. Tambien conviene evitar la indexacion de columnas con baja cardinalidad, como campos booleanos, a menos que participen en un indice compuesto o parcial. ## Anti-patrones Comunes en Consultas SQL Conocer los anti-patrones de escritura SQL es tan importante como dominar las tecnicas de optimizacion. Existen errores frecuentes que, a pesar de producir resultados correctos en apariencia, neutralizan las optimizaciones del planificador de consultas y generan escaneos secuenciales innecesarios. El primer anti-patron consiste en aplicar funciones sobre columnas indexadas. Cuando se envuelve una columna en una funcion, el valor almacenado en el indice deja de coincidir con el valor que se compara, y el planificador no puede utilizar el indice. La solucion es reescribir la condicion como una comparacion de rango. ```sql -- anti_patterns.sql -- BAD: function on indexed column disables the index SELECT * FROM orders WHERE EXTRACT(YEAR FROM order_date) = 2026; -- GOOD: range comparison uses the index SELECT * FROM orders WHERE order_date >= '2026-01-01' AND order_date < '2027-01-01'; ``` El segundo anti-patron, y uno de los mas peligrosos, involucra el uso de NOT IN con subconsultas que pueden contener valores NULL. En la logica ternaria de SQL, cualquier comparacion con NULL produce UNKNOWN, lo que hace que NOT IN devuelva un conjunto de resultados vacio cuando al menos un valor de la subconsulta es NULL. NOT EXISTS maneja correctamente esta situacion y constituye la alternativa recomendada en todos los casos. ```sql -- not_in_null_trap.sql -- BAD: returns empty if any customer_id is NULL in subquery SELECT * FROM customers WHERE customer_id NOT IN ( SELECT customer_id FROM orders ); -- GOOD: NOT EXISTS handles NULLs correctly SELECT * FROM customers c WHERE NOT EXISTS ( SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id ); ``` Este problema con NOT IN y NULL es una pregunta recurrente en entrevistas tecnicas. Los candidatos que lo identifican de forma proactiva, sin que el entrevistador lo sugiera, demuestran un nivel de atencion al detalle que marca la diferencia respecto a otros postulantes. > **Recomendacion para la practica** > > Para desarrollar fluidez real con estos patrones de SQL, se recomienda combinar la refactorizacion de subconsultas con el analisis de planes EXPLAIN en cada ejercicio de practica. Este enfoque dual permite construir la intuicion diagnostica que los entrevistadores buscan: no solo saber escribir la consulta correcta, sino tambien entender como la ejecuta el motor de base de datos y donde se puede mejorar. ## Conclusion Dominar SQL avanzado marca una diferencia tangible en los procesos de seleccion para analistas de datos en 2026. Los conceptos clave que debe manejar todo candidato preparado son los siguientes: - Las subconsultas correlacionadas se reejecutan por cada fila del resultado externo. Refactorizarlas a CTEs o funciones de ventana mejora sustancialmente el rendimiento sobre conjuntos de datos grandes - EXISTS ofrece mejor rendimiento que IN para verificaciones de pertenencia, particularmente cuando la subconsulta devuelve muchas filas o contiene valores NULL - La agregacion condicional con CASE constituye la tecnica de pivot portable y universalmente aceptada. Dominarla antes de aprender la sintaxis PIVOT especifica de cada motor es la estrategia correcta - EXPLAIN ANALYZE revela el plan de ejecucion real de una consulta. El foco debe estar en identificar escaneos secuenciales evitables, evaluar la precision de las estimaciones de filas y comprender la estrategia de join seleccionada - En indices compuestos, el orden de las columnas debe coincidir con los patrones de filtro de las consultas. La regla del prefijo mas a la izquierda determina la utilizabilidad del indice - Los indices parciales y de cobertura reducen las operaciones de lectura para patrones de consulta especificos sin imponer la sobrecarga de un indice sobre la tabla completa - Es fundamental evitar funciones sobre columnas indexadas, NOT IN con valores NULL y SELECT * en consultas de produccion --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/es/blog/data-analytics/advanced-sql-data-analyst-interviews