B3-T3: SQL — LENGUAJE DE CONSULTA ESTRUCTURADO
Tema muy preguntado y práctico. Las consultas SELECT con JOINs, subconsultas y funciones de agregación son casi fijas. También caen preguntas sobre DDL (restricciones, ALTER TABLE), DCL (permisos), y conceptos de PL/SQL (cursores, excepciones, triggers). Practica interpretando consultas SQL — en el examen suelen presentar una consulta y preguntar qué devuelve.
CATEGORÍAS DEL LENGUAJE SQL
| Categoría | Siglas | Sentencias | Función |
| DDL | Data Definition Language | CREATE, ALTER, DROP, TRUNCATE | Definir y modificar la estructura de objetos (tablas, índices, vistas) |
| DML | Data Manipulation Language | SELECT, INSERT, UPDATE, DELETE, MERGE | Consultar y manipular datos |
| DCL | Data Control Language | GRANT, REVOKE | Gestionar permisos y privilegios |
| TCL | Transaction Control Language | COMMIT, ROLLBACK, SAVEPOINT | Gestionar transacciones |
Examen: TRUNCATE es DDL (no DML) — borra todas las filas de una tabla sin generar log de transacciones individual por fila, no se puede hacer ROLLBACK (en la mayoría de SGBD), y resetea los contadores de autoincremento. DELETE es DML — borra fila a fila, genera log, permite ROLLBACK.
DDL — DEFINICIÓN DE DATOS
CREATE TABLE
| Restricción (constraint) | Descripción | Ejemplo |
| PRIMARY KEY | Identifica unívocamente cada fila. NOT NULL + UNIQUE implícitos | id INT PRIMARY KEY |
| FOREIGN KEY | Referencia la PK de otra tabla. Mantiene integridad referencial | FOREIGN KEY (dept_id) REFERENCES departamentos(id) |
| UNIQUE | No permite valores duplicados (permite NULLs múltiples en algunos SGBD) | email VARCHAR(100) UNIQUE |
| NOT NULL | No permite valores nulos | nombre VARCHAR(50) NOT NULL |
| CHECK | Condición que deben cumplir los datos | CHECK (edad >= 18) |
| DEFAULT | Valor por defecto si no se especifica | activo BOOLEAN DEFAULT TRUE |
ALTER TABLE
| Operación | Sintaxis |
| Añadir columna | ALTER TABLE t ADD COLUMN col tipo; |
| Eliminar columna | ALTER TABLE t DROP COLUMN col; |
| Modificar tipo | ALTER TABLE t ALTER COLUMN col TYPE nuevo_tipo; (PostgreSQL) / MODIFY col nuevo_tipo (MySQL/Oracle) |
| Añadir restricción | ALTER TABLE t ADD CONSTRAINT nombre CHECK (condición); |
| Eliminar restricción | ALTER TABLE t DROP CONSTRAINT nombre; |
| Renombrar tabla | ALTER TABLE t RENAME TO nuevo_nombre; |
Tipos de datos SQL más comunes
| Categoría | Tipo | Descripción |
| Numéricos | INTEGER / INT | Entero de 4 bytes |
BIGINT | Entero de 8 bytes |
DECIMAL(p,s) / NUMERIC(p,s) | Exacto con p dígitos totales y s decimales |
FLOAT / DOUBLE / REAL | Coma flotante (aproximado) |
| Texto | CHAR(n) | Cadena de longitud fija (padding con espacios) |
VARCHAR(n) | Cadena de longitud variable (hasta n caracteres) |
TEXT / CLOB | Texto largo sin límite práctico |
| Fecha/Hora | DATE | Fecha (YYYY-MM-DD) |
TIME | Hora (HH:MM:SS) |
TIMESTAMP | Fecha + hora (con o sin zona horaria) |
| Otros | BOOLEAN | TRUE / FALSE (no estándar en Oracle, se usa NUMBER(1)) |
BLOB | Binary Large Object (imágenes, archivos) |
DML — CONSULTAS SELECT
Orden de ejecución lógico de una consulta
| Orden | Cláusula | Función |
| 1 | FROM / JOIN | Define las tablas origen y los JOINs |
| 2 | WHERE | Filtra filas antes de agrupar |
| 3 | GROUP BY | Agrupa filas por columnas |
| 4 | HAVING | Filtra grupos después de agrupar |
| 5 | SELECT | Selecciona columnas y expresiones |
| 6 | DISTINCT | Elimina duplicados |
| 7 | ORDER BY | Ordena el resultado |
| 8 | LIMIT / FETCH | Limita el número de filas devueltas |
Examen: WHERE filtra antes de agrupar (no puede usar funciones de agregación). HAVING filtra después de agrupar (puede usar funciones de agregación). Pregunta típica: "¿Cuál es la diferencia entre WHERE y HAVING?"
Tipos de JOIN
| JOIN | Resultado | Filas sin pareja |
| INNER JOIN | Solo filas con correspondencia en ambas tablas | Se descartan |
| LEFT (OUTER) JOIN | Todas las filas de la tabla izquierda + las que coincidan de la derecha | Filas izq. sin pareja → NULLs en columnas der. |
| RIGHT (OUTER) JOIN | Todas las filas de la tabla derecha + las que coincidan de la izquierda | Filas der. sin pareja → NULLs en columnas izq. |
| FULL (OUTER) JOIN | Todas las filas de ambas tablas | NULLs donde no hay correspondencia |
| CROSS JOIN | Producto cartesiano (todas las combinaciones) | No aplica (todas se combinan) |
| NATURAL JOIN | INNER JOIN automático sobre columnas con el mismo nombre | Se descartan |
| SELF JOIN | Join de una tabla consigo misma (requiere alias) | Según el tipo de JOIN usado |
Funciones de agregación
| Función | Descripción | Ignora NULLs |
| COUNT(*) | Cuenta todas las filas (incluyendo NULLs) | No |
| COUNT(col) | Cuenta filas donde col no es NULL | Sí |
| COUNT(DISTINCT col) | Cuenta valores distintos no NULL | Sí |
| SUM(col) | Suma de valores | Sí |
| AVG(col) | Media aritmética | Sí |
| MAX(col) | Valor máximo | Sí |
| MIN(col) | Valor mínimo | Sí |
Examen: COUNT(*) cuenta filas (incluye NULLs). COUNT(columna) cuenta solo valores no NULL. AVG ignora NULLs — la media de (10, NULL, 20) es 15, no 10.
Subconsultas
| Tipo | Ubicación | Ejemplo |
| Subconsulta escalar | SELECT, WHERE | SELECT (SELECT MAX(sal) FROM emp) AS max_sal |
| Subconsulta de fila | WHERE (con IN, ANY, ALL) | WHERE dept_id IN (SELECT id FROM depts WHERE loc='Madrid') |
| Subconsulta correlacionada | WHERE (referencia tabla externa) | WHERE sal > (SELECT AVG(sal) FROM emp e2 WHERE e2.dept=e1.dept) |
| Subconsulta en FROM | FROM (inline view / derived table) | FROM (SELECT dept, AVG(sal) media FROM emp GROUP BY dept) sub |
| EXISTS / NOT EXISTS | WHERE | WHERE EXISTS (SELECT 1 FROM pedidos WHERE cliente_id = c.id) |
Operadores de conjuntos
| Operador | Descripción | Duplicados |
| UNION | Combina resultados de dos SELECTs (mismas columnas) | Elimina duplicados |
| UNION ALL | Igual que UNION pero mantiene duplicados | Mantiene |
| INTERSECT | Filas comunes a ambos SELECTs | Elimina duplicados |
| EXCEPT / MINUS | Filas del primer SELECT que no están en el segundo | Elimina duplicados |
Funciones de ventana (window functions)
| Función | Descripción | Ejemplo |
| ROW_NUMBER() | Número secuencial único por fila en la partición | ROW_NUMBER() OVER (PARTITION BY dept ORDER BY sal DESC) |
| RANK() | Ranking con huecos (empates comparten posición, siguiente salta) | 1, 2, 2, 4 |
| DENSE_RANK() | Ranking sin huecos | 1, 2, 2, 3 |
| NTILE(n) | Divide las filas en n grupos | NTILE(4) OVER (ORDER BY sal) — cuartiles |
| LAG(col, n) | Valor de la fila n posiciones anterior | Comparar con el mes anterior |
| LEAD(col, n) | Valor de la fila n posiciones posterior | Comparar con el mes siguiente |
| SUM/AVG/COUNT OVER() | Agregaciones acumulativas o por partición sin agrupar | Running total, media móvil |
Examen: Las window functions se ejecutan después de WHERE, GROUP BY y HAVING. No reducen el número de filas (a diferencia de GROUP BY). La cláusula OVER() es obligatoria. PARTITION BY define grupos; ORDER BY define el orden dentro de cada grupo.
CTE (Common Table Expressions)
Las CTEs (definidas con WITH) son consultas temporales con nombre que se pueden referenciar en la consulta principal. Mejoran la legibilidad y permiten recursividad.
| Tipo | Descripción | Uso |
| CTE simple | WITH nombre AS (SELECT ...) | Legibilidad, evitar subconsultas repetidas |
| CTE recursiva | WITH RECURSIVE nombre AS (base UNION ALL SELECT ... FROM nombre ...) | Jerarquías (organigramas, categorías), series numéricas |
DML — MODIFICACIÓN DE DATOS
| Sentencia | Sintaxis | Notas |
| INSERT | INSERT INTO t (cols) VALUES (vals); | INSERT ... SELECT para insertar desde otra consulta |
| UPDATE | UPDATE t SET col=val WHERE condición; | Sin WHERE actualiza TODAS las filas |
| DELETE | DELETE FROM t WHERE condición; | Sin WHERE borra TODAS las filas (pero genera log) |
| MERGE (UPSERT) | MERGE INTO t USING s ON (condición) WHEN MATCHED THEN UPDATE ... WHEN NOT MATCHED THEN INSERT ... | Insert o update según existencia. No estándar en todos los SGBD |
DCL — CONTROL DE ACCESO
| Sentencia | Sintaxis | Descripción |
| GRANT | GRANT SELECT, INSERT ON tabla TO usuario; | Otorga privilegios a un usuario o rol |
| REVOKE | REVOKE INSERT ON tabla FROM usuario; | Revoca privilegios otorgados |
| GRANT con delegación | GRANT SELECT ON tabla TO usuario WITH GRANT OPTION; | El usuario puede a su vez otorgar ese privilegio a otros |
Privilegios típicos
| Privilegio | Permite |
| SELECT | Consultar datos de la tabla |
| INSERT | Insertar filas |
| UPDATE | Modificar filas existentes |
| DELETE | Borrar filas |
| ALL PRIVILEGES | Todos los privilegios sobre el objeto |
| EXECUTE | Ejecutar procedimiento o función almacenada |
| CREATE TABLE / INDEX / VIEW | Crear objetos en el esquema |
PL/SQL — PROGRAMACIÓN EN BASE DE DATOS
Estructura de un bloque PL/SQL
| Sección | Palabra clave | Descripción | Obligatoria |
| Declaración | DECLARE | Variables, constantes, cursores, excepciones | No |
| Ejecución | BEGIN ... END; | Sentencias SQL y de control de flujo | Sí |
| Excepciones | EXCEPTION | Manejo de errores | No |
Cursores
| Tipo | Descripción | Uso |
| Cursor implícito | Se crea automáticamente para cada sentencia SQL | INSERT, UPDATE, DELETE, SELECT INTO |
| Cursor explícito | Declarado por el programador para recorrer un conjunto de resultados fila a fila | Procesamiento fila a fila (OPEN → FETCH → CLOSE) |
| Cursor FOR loop | Cursor implícito con FOR que abre, itera y cierra automáticamente | Forma más simple de iterar resultados |
| REF CURSOR | Cursor dinámico que puede asociarse a distintas consultas en ejecución | Procedimientos que devuelven result sets |
Atributos de cursor implícito
| Atributo | Tipo | Descripción |
| SQL%FOUND | BOOLEAN | TRUE si la última sentencia afectó al menos una fila |
| SQL%NOTFOUND | BOOLEAN | TRUE si no afectó ninguna fila |
| SQL%ROWCOUNT | NUMBER | Número de filas afectadas |
| SQL%ISOPEN | BOOLEAN | Siempre FALSE para cursores implícitos (se cierran automáticamente) |
Excepciones PL/SQL predefinidas
| Excepción | ORA-Code | Causa |
| NO_DATA_FOUND | ORA-01403 | SELECT INTO no devolvió ninguna fila |
| TOO_MANY_ROWS | ORA-01422 | SELECT INTO devolvió más de una fila |
| DUP_VAL_ON_INDEX | ORA-00001 | Inserción viola restricción UNIQUE |
| ZERO_DIVIDE | ORA-01476 | División por cero |
| VALUE_ERROR | ORA-06502 | Error de conversión o truncamiento |
| INVALID_CURSOR | ORA-01001 | Operación ilegal con un cursor (ej. FETCH de cursor cerrado) |
Triggers
| Aspecto | Opciones | Descripción |
| Momento | BEFORE / AFTER / INSTEAD OF | Cuándo se ejecuta respecto a la operación DML |
| Evento | INSERT / UPDATE / DELETE | Qué operación lo dispara |
| Nivel | FOR EACH ROW / FOR EACH STATEMENT | Se ejecuta por cada fila afectada o una vez por sentencia |
| Referencias | :NEW / :OLD | Valores nuevos y antiguos de la fila (solo en row-level triggers) |
Examen: INSTEAD OF triggers solo se usan sobre vistas (para hacer que vistas no actualizables acepten DML). :NEW contiene los valores nuevos (INSERT/UPDATE). :OLD contiene los valores anteriores (UPDATE/DELETE). En un INSERT, :OLD es NULL; en un DELETE, :NEW es NULL.
Procedimientos y funciones
| Aspecto | Procedimiento | Función |
| Retorno | No devuelve valor directamente (usa OUT params) | Devuelve un valor con RETURN |
| Uso en SELECT | No se puede usar en una consulta SQL | Sí (si no tiene efectos secundarios) |
| Llamada | EXECUTE proc(params) | SELECT func(params) FROM dual |
| Parámetros | IN, OUT, IN OUT | IN (solo entrada) |
FUNCIONES SQL COMUNES
Funciones de cadena
| Función | Descripción | Ejemplo |
| UPPER / LOWER | Mayúsculas / minúsculas | UPPER('hola') → 'HOLA' |
| LENGTH / LEN | Longitud de la cadena | LENGTH('abc') → 3 |
| SUBSTRING / SUBSTR | Extraer subcadena | SUBSTR('abcdef', 2, 3) → 'bcd' |
| TRIM / LTRIM / RTRIM | Eliminar espacios | TRIM(' hola ') → 'hola' |
| CONCAT / || | Concatenar cadenas | 'a' || 'b' → 'ab' |
| REPLACE | Sustituir texto | REPLACE('abc', 'b', 'x') → 'axc' |
| COALESCE | Primer valor no NULL de la lista | COALESCE(NULL, NULL, 'x') → 'x' |
| NVL / IFNULL / ISNULL | Si NULL, devuelve valor alternativo | NVL(comision, 0) (Oracle) |
Funciones de fecha
| Función | SGBD | Descripción |
| SYSDATE / NOW() / CURRENT_TIMESTAMP | Oracle / MySQL / Estándar | Fecha y hora actual |
| EXTRACT(part FROM date) | Estándar | Extraer año, mes, día, hora de una fecha |
| DATE_ADD / INTERVAL | MySQL / PostgreSQL | Sumar/restar intervalos a fechas |
| TO_DATE / TO_CHAR | Oracle | Conversión entre fecha y cadena con formato |
FUENTES PÚBLICAS
Este resumen ha sido elaborado íntegramente a partir de fuentes de dominio público. No se ha utilizado material con copyright de terceros ni material de preparadores.
| Fuente | Tipo | Referencia |
| ISO/IEC 9075 — SQL Standard | Estándar | ISO (conceptos públicos) |
| PostgreSQL Documentation | Documentación oficial | postgresql.org/docs |
| Oracle SQL Reference | Documentación oficial | docs.oracle.com |
| Oracle PL/SQL Reference | Documentación oficial | docs.oracle.com |
| MySQL Reference Manual | Documentación oficial | dev.mysql.com/doc |