{
  "assessmentTests": {
    "sql_test": {
      "name": "Test de SQL",
      "desc": "30 preguntas de escenarios sobre filtrado, NULL, combinaciones, agregación, subconsultas y funciones de ventana — descubre si tu SQL coincide con lo que una oferta de empleo entiende por competencia en SQL.",
      "recommendation": "Tu perfil de habilidades en SQL",
      "results": {
        "beginner": {
          "name": "Principiante",
          "desc": "Puedes escribir una instrucción SELECT que funciona y filtrar en un par de condiciones, pero las preguntas que no respondiste correctamente se agrupan alrededor del manejo de NULL y mecánicas de combinación en lugar de sintaxis — comparar una columna con NULL usando =, lo que LEFT JOIN realmente preserva, cómo funcionan los límites de BETWEEN. Nada de esto se trata de ser malo con bases de datos; estas son las reglas específicas que engañan a la gente que aprendió SQL por ensayo y error en lugar de del estándar. Importan en el trabajo porque cada una es un lugar donde una consulta devuelve un recuento de filas plausible pero incorrecto.",
          "recommendation": "Comienza con tres cosas, en este orden: por qué WHERE col = NULL nunca coincide nada (e IS NULL es obligatorio), cómo INNER JOIN descarta filas sin coincidencia mientras LEFT JOIN las mantiene, y los límites exactos que incluye BETWEEN. El tutorial de SQL de Mode Analytics y la documentación de PostgreSQL cubren los tres con ejemplos ejecutables."
        },
        "intermediate": {
          "name": "Intermedio",
          "desc": "Manejas consultas de informes cotidianos cómodamente — combinaciones, GROUP BY, filtrado directo — y no te ralentizaría el trabajo rutinario de paneles o análisis ad hoc. La brecha entre aquí y Avanzado es principalmente lo que sucede cuando las cláusulas interactúan: una cláusula WHERE en la tabla combinada que silenciosamente convierte un LEFT JOIN en un INNER JOIN, una combinación que multiplica los recuentos de filas antes de que se aplique un agregado, un NOT IN que silenciosamente devuelve nada porque un NULL se coló en la subconsulta. Ese es el tipo de errores que pasan un rápido vistazo y solo aparecen cuando alguien compara el total con un informe diferente.",
          "recommendation": "Enfócate en cómo interactúan las cláusulas en lugar de qué hace cada una por separado: filtrado WHERE en columnas RIGHT de un LEFT JOIN, multiplicación de filas de combinaciones uno-a-muchos antes de que se aplique un agregado, y por qué NOT IN se rompe en presencia de NULLs (EXISTS generalmente no). Luego HAVING versus WHERE, ya que esa división engaña a gente que ya conoce ambas cláusulas."
        },
        "advanced": {
          "name": "Avanzado",
          "desc": "Este es el nivel que la mayoría de ofertas de empleo entienden por «SQL fuerte». Lees una consulta con múltiples combinaciones y puedes predecir su recuento de filas antes de ejecutarla, sabes por qué un conjunto de resultados cambió en lugar de solo que lo hizo, y llegas a un CTE o una función de ventana en lugar de una subconsulta anidada cuando esa es la herramienta más clara. Lo que separa esta banda de la superior es el lado defensivo del trabajo: saber cuál función de clasificación usar cuando los empates importan, qué aísla una transacción de una sesión concurrente, y qué hace realmente una regla ON DELETE faltante a nivel de base de datos.",
          "recommendation": "Profundiza en las partes que protegen datos que otras personas también toquetean: la diferencia entre RANK, DENSE_RANK y ROW_NUMBER bajo empates, qué hace COMMIT visible y a quién, y comportamiento de clave foránea en DELETE. Usa los análisis profundos del boletín The Index o SQL for Devs sobre funciones de ventana e aislamiento de transacciones como el siguiente paso para ambos."
        },
        "expert": {
          "name": "Experto",
          "desc": "Puntuaste en la parte superior de cada sección — filtrado y semántica NULL, combinaciones y operaciones de conjunto, agregación y subconsultas, y funciones de ventana, CTE e restricciones. Prácticamente, eso significa que puedes recibir una consulta de informe con múltiples combinaciones de un desconocido y explicar por qué devuelve el recuento de filas que devuelve, no solo lo que la sintaxis dice que debería, que es la habilidad más difícil y más valiosa. A este nivel el lenguaje de consulta rara vez es el factor limitante; el límite es generalmente diseño de esquema o el tamaño de los datos por debajo.",
          "recommendation": "Los retornos ahora están en planes de ejecución y diseño: lectura de salida de EXPLAIN antes de asumir que una consulta es lenta, estrategia de indexación como un tradeoff contra costo de escritura en lugar de una ganancia libre, y decisiones de normalización que se mantienen mientras un esquema crece. Si estás siendo evaluado para un rol, describe un error de consulta como la multiplicación de combinación o la trampa NOT IN/NULL que encontraste en producción en lugar de nombrar características de SQL — demuestra el razonamiento, no solo el vocabulario."
        }
      },
      "questions": [
        {
          "question": "Una tabla tiene una columna age que puede ser nula. Ejecutas SELECT * FROM users WHERE age = NULL. ¿Cuántas filas devuelve esto, incluso si hay varias filas con age establecida en NULL?",
          "options": [
            {
              "icon": "",
              "label": "Toda fila donde age es NULL, porque = coincide con NULL como cualquier otro valor"
            },
            {
              "icon": "",
              "label": "Cero — comparar cualquier cosa con NULL usando = produce UNKNOWN, nunca TRUE, así que ninguna fila coincide; IS NULL es obligatorio"
            },
            {
              "icon": "",
              "label": "Un error de sintaxis — NULL no puede aparecer en el lado derecho de ="
            },
            {
              "icon": "",
              "label": "Toda fila de la tabla, porque las comparaciones con NULL por defecto son TRUE"
            }
          ]
        },
        {
          "question": "Ejecutas SELECT DISTINCT department, role FROM employees. ¿De qué elimina duplicados DISTINCT?",
          "options": [
            {
              "icon": "",
              "label": "La combinación de department y role juntos — una fila solo se elimina si ambas columnas coinciden exactamente con otra fila"
            },
            {
              "icon": "",
              "label": "Solo valores de department duplicados, manteniendo cada role"
            },
            {
              "icon": "",
              "label": "Solo valores de role duplicados, manteniendo cada department"
            },
            {
              "icon": "",
              "label": "Nada — DISTINCT solo funciona con una sola columna"
            }
          ]
        },
        {
          "question": "Un nombre de columna se filtra con WHERE name LIKE 'A_'. ¿Cuál de estos valores coincide: 'A', 'Al', 'Ana', 'Ally'?",
          "options": [
            {
              "icon": "",
              "label": "'A' — el guión bajo es opcional y coincide con cero o más caracteres"
            },
            {
              "icon": "",
              "label": "'Al' — el guión bajo coincide exactamente con un carácter, así que LIKE 'A_' coincide con cualquier cadena de dos caracteres que empieza con A"
            },
            {
              "icon": "",
              "label": "'Ana' y 'Ally' — el guión bajo coincide con cualquier número de caracteres finales"
            },
            {
              "icon": "",
              "label": "Los cuatro valores coinciden, porque LIKE ignora la longitud"
            }
          ]
        },
        {
          "question": "Una columna price se filtra con WHERE price BETWEEN 10 AND 20. ¿Se incluyen filas con price exactamente 10 o exactamente 20?",
          "options": [
            {
              "icon": "",
              "label": "No — BETWEEN excluye ambos extremos"
            },
            {
              "icon": "",
              "label": "Sí — BETWEEN es inclusivo en ambos extremos, equivalente a price >= 10 AND price <= 20"
            },
            {
              "icon": "",
              "label": "Solo price = 10 se incluye; el límite superior es exclusivo"
            },
            {
              "icon": "",
              "label": "Solo price = 20 se incluye; el límite inferior es exclusivo"
            }
          ]
        },
        {
          "question": "Una tabla orders tiene 10 filas, y 3 de ellas tienen shipped_date NULL. ¿Qué devuelve SELECT COUNT(*) FROM orders, y qué devuelve SELECT COUNT(shipped_date) FROM orders?",
          "options": [
            {
              "icon": "",
              "label": "10, luego 10 — COUNT siempre cuenta filas independientemente de NULLs"
            },
            {
              "icon": "",
              "label": "7, luego 7 — ambas formas saltan filas NULL"
            },
            {
              "icon": "",
              "label": "10, luego 7 — COUNT(*) cuenta toda fila, COUNT(column) cuenta solo filas donde esa columna no es NULL"
            },
            {
              "icon": "",
              "label": "10, luego 3 — COUNT(column) cuenta solo los valores NULL"
            }
          ]
        },
        {
          "question": "Ejecutas SELECT name, salary FROM employees ORDER BY 2 DESC. ¿A qué se refiere el 2?",
          "options": [
            {
              "icon": "",
              "label": "Un error de sintaxis — ORDER BY solo acepta nombres de columna, no números"
            },
            {
              "icon": "",
              "label": "La segunda fila del resultado"
            },
            {
              "icon": "",
              "label": "Un valor literal de 2, usado como desempate"
            },
            {
              "icon": "",
              "label": "La segunda columna en la lista SELECT, salary — ORDER BY acepta el número de posición de una columna como atajo"
            }
          ]
        },
        {
          "question": "En SQL estándar, ¿a qué se evalúa 'Ana' || ' ' || 'Lee'?",
          "options": [
            {
              "icon": "",
              "label": "Un error de sintaxis — SQL no tiene operador de concatenación"
            },
            {
              "icon": "",
              "label": "3 — || se trata como un OR booleano y devuelve un recuento"
            },
            {
              "icon": "",
              "label": "'AnaLee' — || concatena sin preservar espacios"
            },
            {
              "icon": "",
              "label": "'Ana Lee' — || es el operador de concatenación de cadenas SQL estándar"
            }
          ]
        },
        {
          "question": "¿Cuál de estas es exactamente equivalente a WHERE status IN ('open', 'pending', 'review')?",
          "options": [
            {
              "icon": "",
              "label": "WHERE status = 'open' AND status = 'pending' AND status = 'review'"
            },
            {
              "icon": "",
              "label": "WHERE status != 'open' OR status != 'pending' OR status != 'review'"
            },
            {
              "icon": "",
              "label": "WHERE status = 'open' OR status = 'pending' OR status = 'review'"
            },
            {
              "icon": "",
              "label": "WHERE status LIKE 'open,pending,review'"
            }
          ]
        },
        {
          "question": "customers tiene 100 filas; 20 de ellas nunca han realizado un pedido. Ejecutas SELECT c.id FROM customers c INNER JOIN orders o ON c.id = o.customer_id. ¿Aparecen los 20 clientes sin pedidos en el resultado?",
          "options": [
            {
              "icon": "",
              "label": "Sí, una vez cada uno, con o.id mostrado como NULL"
            },
            {
              "icon": "",
              "label": "Sí, pero solo si también aparecen en una cláusula WHERE"
            },
            {
              "icon": "",
              "label": "No — INNER JOIN solo devuelve filas que tienen una coincidencia en ambas tablas, así que los clientes sin pedidos se descartan completamente"
            },
            {
              "icon": "",
              "label": "Sí, duplicados una vez por columna en orders"
            }
          ]
        },
        {
          "question": "Quieres cada cliente independientemente de si tiene pedidos, así que escribes SELECT c.id, o.total FROM customers c LEFT JOIN orders o ON c.id = o.customer_id WHERE o.total > 100. ¿Sigue devolviendo clientes sin pedidos?",
          "options": [
            {
              "icon": "",
              "label": "No — filtrar en o.total en la cláusula WHERE descarta las filas NULL que LEFT JOIN produjo para clientes sin coincidencia, así se comporta como INNER JOIN"
            },
            {
              "icon": "",
              "label": "Sí — LEFT JOIN siempre preserva cada fila de customers sin importar qué siga"
            },
            {
              "icon": "",
              "label": "Sí, con o.total mostrado como 0 para clientes sin pedidos"
            },
            {
              "icon": "",
              "label": "No — LEFT JOIN silenciosamente se convierte a sí mismo en RIGHT JOIN cuando se añade una cláusula WHERE"
            }
          ]
        },
        {
          "question": "Una tabla employees tiene una columna id y una columna manager_id que apunta a la fila de otro id. Para listar cada empleado al lado del nombre de su gestor, combinas la tabla consigo misma: SELECT e.name, m.name FROM employees e JOIN employees m ON e.manager_id = m.id. ¿Cómo se llama este patrón?",
          "options": [
            {
              "icon": "",
              "label": "Una combinación cruzada — cada empleado se empareja con cada gestor"
            },
            {
              "icon": "",
              "label": "Una combinación recursiva — recupera la cadena de gestión completa"
            },
            {
              "icon": "",
              "label": "Una autocombinación — la misma tabla se combina consigo misma usando dos alias diferentes"
            },
            {
              "icon": "",
              "label": "Esto es SQL inválido — una tabla no puede combinarse consigo misma"
            }
          ]
        },
        {
          "question": "Dos consultas SELECT con las mismas columnas se combinan con UNION. Si ambas consultas devuelven una fila idéntica, ¿cuántas copias de esa fila aparecen en el resultado final?",
          "options": [
            {
              "icon": "",
              "label": "Una — UNION elimina filas duplicadas en el resultado combinado; UNION ALL mantendría ambas copias"
            },
            {
              "icon": "",
              "label": "Dos — UNION mantiene toda fila de ambas consultas"
            },
            {
              "icon": "",
              "label": "Cero — UNION elimina cualquier fila que aparece en ambas consultas"
            },
            {
              "icon": "",
              "label": "Depende de cuál consulta listó la fila primero"
            }
          ]
        },
        {
          "question": "La tabla sizes tiene 3 filas y colors tiene 4 filas. ¿Cuántas filas devuelve SELECT * FROM sizes CROSS JOIN colors?",
          "options": [
            {
              "icon": "",
              "label": "7 — CROSS JOIN suma los recuentos de filas juntos"
            },
            {
              "icon": "",
              "label": "12 — una CROSS JOIN devuelve cada combinación posible de filas de ambas tablas (3 x 4)"
            },
            {
              "icon": "",
              "label": "3 — CROSS JOIN devuelve una fila por cada fila en la primera tabla"
            },
            {
              "icon": "",
              "label": "0 — CROSS JOIN requiere una condición ON o devuelve nada"
            }
          ]
        },
        {
          "question": "orders tiene 1 fila para el pedido #100, y order_items tiene 3 filas para el pedido #100 (una por artículo). Ejecutas SELECT o.id, o.total FROM orders o JOIN order_items i ON o.id = i.order_id WHERE o.id = 100. ¿Cuántas filas devuelven para el pedido #100?",
          "options": [
            {
              "icon": "",
              "label": "3 — la combinación produce una fila de salida por cada fila coincidente en order_items, así que la fila única del pedido #100 se repite una vez por artículo"
            },
            {
              "icon": "",
              "label": "1 — orders solo tiene una fila para el pedido #100, así que la combinación no puede producir más"
            },
            {
              "icon": "",
              "label": "4 — una fila para el pedido más una por artículo"
            },
            {
              "icon": "",
              "label": "0 — combinar una tabla de una fila con una tabla de tres filas en una clave no única falla"
            }
          ]
        },
        {
          "question": "SELECT c.name, o.id FROM customers c RIGHT JOIN orders o ON c.id = o.customer_id devuelve las mismas filas que ¿cuál de estas?",
          "options": [
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM customers c INNER JOIN orders o ON c.id = o.customer_id"
            },
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM orders o LEFT JOIN customers c ON c.id = o.customer_id — cambiar el orden de tabla y usar LEFT JOIN en lugar de RIGHT JOIN es equivalente"
            },
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM customers c LEFT JOIN orders o ON c.id = o.customer_id"
            },
            {
              "icon": "",
              "label": "SELECT c.name, o.id FROM orders o CROSS JOIN customers c"
            }
          ]
        },
        {
          "question": "En SQL estándar, ejecutas SELECT department, name, AVG(salary) FROM employees GROUP BY department. ¿Es una consulta válida?",
          "options": [
            {
              "icon": "",
              "label": "Sí — GROUP BY solo necesita incluir department porque se lista primero"
            },
            {
              "icon": "",
              "label": "No — name se selecciona pero ni se agrega ni se lista en GROUP BY, y SQL estándar requiere que toda columna seleccionada no agregada aparezca en la cláusula GROUP BY"
            },
            {
              "icon": "",
              "label": "Sí — SQL automáticamente elige un name arbitrario por department"
            },
            {
              "icon": "",
              "label": "No — AVG() no puede combinarse con GROUP BY en la misma consulta"
            }
          ]
        },
        {
          "question": "Quieres departments cuyo salario promedio excede 80000. ¿Qué cláusula filtra en un valor agregado como AVG(salary) después del agrupamiento — WHERE o HAVING?",
          "options": [
            {
              "icon": "",
              "label": "WHERE — HAVING solo se usa con consultas UNION"
            },
            {
              "icon": "",
              "label": "Cualquiera funciona idénticamente con funciones de agregación"
            },
            {
              "icon": "",
              "label": "Ninguna — el filtrado de agregación requiere una subconsulta"
            },
            {
              "icon": "",
              "label": "HAVING — WHERE filtra filas individuales antes de que ocurra la agrupación, HAVING filtra grupos después de la agregación"
            }
          ]
        },
        {
          "question": "Escribes SELECT salary * 1.1 AS new_salary FROM employees WHERE new_salary > 50000. ¿Funciona esto?",
          "options": [
            {
              "icon": "",
              "label": "Sí — los alias definidos en SELECT siempre están disponibles para WHERE en la misma consulta"
            },
            {
              "icon": "",
              "label": "Sí, pero solo para alias numéricos"
            },
            {
              "icon": "",
              "label": "No — AS no está permitido dentro de una consulta filtrada por WHERE"
            },
            {
              "icon": "",
              "label": "No — WHERE se evalúa antes de que SELECT asigne el alias new_salary, así que el alias no existe aún en ese punto en la ejecución"
            }
          ]
        },
        {
          "question": "SELECT name FROM employees e WHERE salary > (SELECT AVG(salary) FROM employees WHERE department = e.department). ¿Por qué se llama esto una subconsulta correlacionada?",
          "options": [
            {
              "icon": "",
              "label": "Porque usa una JOIN en lugar de una cláusula WHERE"
            },
            {
              "icon": "",
              "label": "La subconsulta interna referencia e.department de la consulta externa, así que debe reevaluarse para cada fila que la consulta externa considera"
            },
            {
              "icon": "",
              "label": "Porque devuelve más de una columna"
            },
            {
              "icon": "",
              "label": "Porque se ejecuta exactamente una vez antes de que la consulta externa comience"
            }
          ]
        },
        {
          "question": "Una subconsulta SELECT manager_id FROM employees devuelve algunos valores NULL junto con ids reales. Ejecutas SELECT name FROM employees WHERE id NOT IN (SELECT manager_id FROM employees). ¿Qué sucede?",
          "options": [
            {
              "icon": "",
              "label": "Devuelve cada empleado que no es gestor, ignorando los NULLs"
            },
            {
              "icon": "",
              "label": "Devuelve cero filas — un único NULL en la lista NOT IN hace que cada comparación sea UNKNOWN, así que ninguna fila puede satisfacer la condición"
            },
            {
              "icon": "",
              "label": "Genera un error porque NOT IN no puede usarse con subconsultas"
            },
            {
              "icon": "",
              "label": "Devuelve cada empleado, ya que NULL se trata como un comodín"
            }
          ]
        },
        {
          "question": "SELECT name FROM customers c WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id). ¿Qué devuelve esto?",
          "options": [
            {
              "icon": "",
              "label": "Cada cliente que tiene al menos una fila en orders — EXISTS solo verifica si la subconsulta devuelve filas, no qué valores contienen"
            },
            {
              "icon": "",
              "label": "Cada cliente, porque SELECT 1 siempre devuelve true"
            },
            {
              "icon": "",
              "label": "Un error, porque la subconsulta selecciona un número en lugar de un nombre de columna"
            },
            {
              "icon": "",
              "label": "Solo clientes con exactamente un pedido"
            }
          ]
        },
        {
          "question": "Escribes SELECT name, (SELECT order_id FROM orders WHERE customer_id = c.id) AS last_order FROM customers c, y un cliente dado tiene 3 filas en orders. ¿Qué sucede cuando se ejecuta esta consulta?",
          "options": [
            {
              "icon": "",
              "label": "Devuelve el primer order_id coincidente e ignora silenciosamente los otros dos"
            },
            {
              "icon": "",
              "label": "Devuelve una lista separada por comas de los tres order_ids"
            },
            {
              "icon": "",
              "label": "Devuelve 3 filas para ese cliente, una por cada pedido"
            },
            {
              "icon": "",
              "label": "Genera un error en tiempo de ejecución — una subconsulta escalar en la lista SELECT debe devolver como máximo una fila, y esta devuelve tres"
            }
          ]
        },
        {
          "question": "Cuatro filas empatan con la puntuación más alta. Usando RANK() ORDER BY score DESC, los cuatro obtienen rank 1. ¿Qué rank obtiene la siguiente fila hacia abajo?",
          "options": [
            {
              "icon": "",
              "label": "5 — RANK() deja un hueco igual al número de filas empatadas antes de continuar"
            },
            {
              "icon": "",
              "label": "2 — RANK() siempre incrementa exactamente uno después de cualquier empate"
            },
            {
              "icon": "",
              "label": "1 — cada fila subsecuente también obtiene rank 1"
            },
            {
              "icon": "",
              "label": "4 — RANK() reinicia el conteo del número de empates"
            }
          ]
        },
        {
          "question": "Cuatro filas empatan con la puntuación más alta. Usando DENSE_RANK() ORDER BY score DESC, los cuatro obtienen rank 1. ¿Qué rank obtiene la siguiente fila hacia abajo?",
          "options": [
            {
              "icon": "",
              "label": "5 — DENSE_RANK() se comporta exactamente como RANK()"
            },
            {
              "icon": "",
              "label": "1 — DENSE_RANK() asigna el mismo rank a cada fila restante"
            },
            {
              "icon": "",
              "label": "2 — DENSE_RANK() nunca deja huecos, así que el siguiente valor distinto siempre obtiene el siguiente rank consecutivo"
            },
            {
              "icon": "",
              "label": "3 — DENSE_RANK() salta un rank por grupo empatado"
            }
          ]
        },
        {
          "question": "SUM(amount) OVER (PARTITION BY region ORDER BY amount) se añade a una consulta. ¿Qué hace PARTITION BY region aquí?",
          "options": [
            {
              "icon": "",
              "label": "Reinicia la suma acumulada por separado para cada región, en lugar de acumular en todo el conjunto de resultados"
            },
            {
              "icon": "",
              "label": "Filtra los resultados a una única región"
            },
            {
              "icon": "",
              "label": "Agrupa y colapsa las filas a una por región, como GROUP BY"
            },
            {
              "icon": "",
              "label": "Ordena las regiones alfabéticamente antes de sumar"
            }
          ]
        },
        {
          "question": "ROW_NUMBER() OVER (ORDER BY score DESC) se aplica a cinco filas, dos de las cuales tienen exactamente la misma puntuación. ¿Pueden dos filas recibir nunca el mismo número de fila?",
          "options": [
            {
              "icon": "",
              "label": "Sí — las filas empatadas siempre comparten el mismo número de fila"
            },
            {
              "icon": "",
              "label": "Solo si también se usa PARTITION BY"
            },
            {
              "icon": "",
              "label": "Depende de si el empate está en la posición primera o última"
            },
            {
              "icon": "",
              "label": "No — ROW_NUMBER() siempre asigna un entero único y estrictamente creciente a cada fila, incluso cuando los valores empatan"
            }
          ]
        },
        {
          "question": "WITH high_earners AS (SELECT * FROM employees WHERE salary > 100000) SELECT department, COUNT(*) FROM high_earners GROUP BY department. ¿Qué es high_earners?",
          "options": [
            {
              "icon": "",
              "label": "Una expresión de tabla común (CTE) — un conjunto de resultados temporal con nombre que el resto de la consulta puede referenciar como una tabla"
            },
            {
              "icon": "",
              "label": "Una tabla permanente creada en la base de datos"
            },
            {
              "icon": "",
              "label": "Una vista que persiste después de que la consulta termina"
            },
            {
              "icon": "",
              "label": "Un procedimiento almacenado que debe llamarse por separado"
            }
          ]
        },
        {
          "question": "Una columna se declara PRIMARY KEY. ¿Puedes insertar una fila donde esa columna es NULL?",
          "options": [
            {
              "icon": "",
              "label": "Sí — PRIMARY KEY solo aplica unicidad, no NULL-ness"
            },
            {
              "icon": "",
              "label": "Sí, pero solo se permite una fila NULL, como una restricción UNIQUE"
            },
            {
              "icon": "",
              "label": "No — una columna PRIMARY KEY es implícitamente NOT NULL, así que insertar NULL en ella se rechaza"
            },
            {
              "icon": "",
              "label": "Depende de si la columna también tiene un valor por defecto"
            }
          ]
        },
        {
          "question": "Dentro de una transacción abierta, ejecutas un UPDATE pero aún no has ejecutado COMMIT. Desde una segunda conexión separada a la base de datos, ¿es visible esa actualización?",
          "options": [
            {
              "icon": "",
              "label": "Sí — todas las conexiones ven cada escritura en el instante en que se ejecuta"
            },
            {
              "icon": "",
              "label": "Sí, pero solo si la segunda conexión también abre una transacción"
            },
            {
              "icon": "",
              "label": "Depende solo de qué tabla fue actualizada"
            },
            {
              "icon": "",
              "label": "No — un cambio sin confirmar solo es visible dentro de la transacción que lo hizo, hasta que COMMIT lo hace duradero y visible para otros"
            }
          ]
        },
        {
          "question": "products.category_id tiene una restricción FOREIGN KEY que referencia categories.id. Intentas DELETE una fila de categories que aún tiene productos apuntándola, sin regla ON DELETE especificada. ¿Qué sucede?",
          "options": [
            {
              "icon": "",
              "label": "La fila de categoría se borra y los valores products.category_id coincidentes se establecen automáticamente en NULL"
            },
            {
              "icon": "",
              "label": "La fila de categoría se borra y cada producto que la referenciaba también se borra"
            },
            {
              "icon": "",
              "label": "El DELETE se rechaza — el comportamiento predeterminado de clave foránea bloquea borrar una fila referenciada mientras filas dependientes aún la apuntan"
            },
            {
              "icon": "",
              "label": "El DELETE tiene éxito silenciosamente, dejando el category_id de los productos apuntando a una categoría que ya no existe"
            }
          ]
        }
      ],
      "optionOrderVersion": "e0466e547cfd8a45"
    }
  }
}
