T10 - Introducción a SQL

Departamento de Lenguajes y Sistemas Informáticos
Universidad de Sevilla

Objetivos

Contenido

  • Introducción
  • Lenguaje de definición de datos (DDL)
  • Lenguaje de manipulación de datos (DML)
  • Lenguaje de consulta de datos (DQL)
  • Consultas complejas

Contenido

  • Introducción
  • Lenguaje de definición de datos (DDL)
  • Lenguaje de manipulación de datos (DML)
  • Lenguaje de consulta de datos (DQL)
  • Consultas complejas

Introducción a SQL

  • SQL (Structured Query Language) es el lenguaje estándar para definir, manipular y consultar bases de datos relacionales.
  • Puede ser utilizado en lenguajes de programación de propósito general como Java, C, Python o bien en lenguajes específicos del fabricante (p.ej. PL/SQL en Oracle, Transact SQL en MS SQLServer).
  • Se puede distinguir:
    • DDL (Data Definition Language): gestión del esquema de la base de datos (creación, modificación y borrado de tablas, claves, etc.). CREATE, ALTER, DROP
    • DML (Data Manipulation Language): gestión de los datos. INSERT, UPDATE, DELETE
    • DCL (Data Control Language): Control de acceso y permisos. GRANT y REVOKE
    • DQL (Data Query Language): Gestión de consultas. SELECT
    • TCL (Transaction Control Language): gestión de transacciones. COMMIT, ROLLBACK, TRANSACTION

Introducción a SQL

Tutoriales SQL

http://www.w3schools.com/sql/

https://www.tutorialspoint.com/sql/index.htm

https://mariadb.com/kb/en/library/basic-sql-statements/

https://www.hcoe.edu.np/uploads/attachments/r96oytechsacgzi4.pdf

Introducción a SQL

Año Nombre Alias habitual Comentarios
1986 SQL-86 SQL-87* Primera estandarización ANSI (X3.135-1986).
1989 SQL-89 SQL1 Revisión menor de SQL-86.
1992 SQL-92 SQL2 Gran revisión: base del SQL relacional clásico moderno.
1999 SQL:1999 SQL3 Añade PSM (procedimientos), triggers, recursividad (WITH RECURSIVE), tipos/objetos, etc.
2003 SQL:2003 SQL/XML, secuencias y columnas identidad (autonuméricas), mejoras analíticas.
2006 SQL:2006 Consolidación y ampliación de SQL/XML.
2008 SQL:2008 Refinamientos y extensiones de lenguaje (sin ruptura grande).
2011 SQL:2011 Soporte temporal (periodos de aplicación y de sistema).
2016 SQL:2016 JSON en el estándar, row pattern recognition (MATCH_RECOGNIZE) y más analítica.
2023 SQL:2023 Revisión vigente de la familia ISO/IEC 9075 (actualiza múltiples partes).

Fuente: https://www.iso.org/standard/76584.html

Ejemplo: Modelo Conceptual y Relacional

-- Intensión relacional
Departamentos = {departamentoId, nombreDep, localidad}
	PK(departamentoId)
	AK(nombreDep, localidad)

Empleados = {empleadoId, departamentoId, jefeId, 
   nombre, salario, fechaInicial, fechaFinal, comision}
	PK(empleadoId)
	FK(departamentoId)/Departamentos
	FK(jefeId)/Empleados

Transformación del MR a SQL

  • Se creará una tabla por cada relación del modelo relacional.
  • Será necesario la definición de claves primarias y ajenas.
  • El resto de restricciones se definen mediante:
    • CHECK <condición>. Limita los valores a insertar.
    • UNIQUE. Para asegurar que no se repiten valores. (AK)
    • NOT NULL. No admite nulos.
    • En caso de restricciones que no se puedan definir mediante CHECK:
      • STORED PROCEDURE + TRIGGERS.

Contenido

  • Introducción
  • Lenguaje de definición de datos (DDL)
  • Lenguaje de manipulación de datos (DML)
  • Lenguaje de consulta de datos (DQL)
  • Consultas complejas

HeidiSQL

DDL – CREATE TABLE

Modelo relacional:

Departamentos = { departamentoId, nombreDep, localidad }
    PK(departamentoId)
    AK(nombreDep, localidad)

Modelo tecnológico (SQL):

CREATE TABLE departments (
  department_id INT NOT NULL AUTO_INCREMENT,
  department_name VARCHAR(32),
  city VARCHAR(64),
  PRIMARY KEY (department_id),
  UNIQUE (department_name, city)
);

DDL – CREATE TABLE

Empleados = { empleadoId, departamentoId, jefeId, 
   nombre, salario, fechaInicial, fechaFinal, comision }
    PK(empleadoId)
    FK(departamentoId) / Departamentos
    FK(jefeId) / Empleados
    AK(nombre)
CREATE TABLE employees (
  employee_id INT NOT NULL AUTO_INCREMENT,
  department_id INT,
  manager_id INT,
  employee_name VARCHAR(64) NOT NULL,
  salary DECIMAL(6,2) DEFAULT 2000.00,
  start_date DATE,
  end_date DATE,
  commission DOUBLE,
  PRIMARY KEY (employee_id),
  FOREIGN KEY (department_id) REFERENCES departments(department_id)
    ON DELETE SET NULL,
  FOREIGN KEY (manager_id) REFERENCES employees(employee_id),
  UNIQUE (employee_name),
  CHECK (commission >= 0 AND commission <= 1),
  CONSTRAINT ck_employee_dates CHECK (start_date < end_date)
);

DDL - CLAVES

Claves primarias

PRIMARY KEY(tablaId)

Claves alternativas

UNIQUE(atributo) o UNIQUE(atributo1, atributo2…)

Claves ajenas

	FOREIGN KEY(atributo)
           REFERENCES OtraTabla(otraTablaId) ON DELETE:
			- RESTRICT (por defecto)
			- CASCADE
			- SET NULL
			- SET DEFAULT
	   ON UPDATE: ...

DDL – Integridad referencial

https://mariadb.com/kb/en/library/foreign-keys/

DDL – Reglas de negocio

atributo Tipo DEFAULT(valor): Define cuál será el ‘valor’ que se le asigne al ‘atributo’ cuando no se especifique ningún valor.

CHECK (expr): Define una restricción que deben cumplir los valores de uno o varios atributos.

CONSTRAINT nombre CHECK (expr): Similar al anterior, dando un nombre a la restricción que aparecerá en caso de error.

DDL - Tipos de datos

https://mariadb.com/kb/en/library/data-types/

Numéricos: TINYINT, BOOLEAN, SMALLINT, MEDIUMINT, INT, BIGINT, DECIMAL, FLOAT, DOUBLE, BIT…

Cadenas: CHAR, VARCHAR, TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT, ENUM…

Binarios: BINARY, VARBINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB…

Fechas: DATE, TIME, DATETIME, YEAR…

Geometrías: POINT, LINESTRING, POLYGON, MULTIPOINT…

Contenido

  • Introducción
  • Lenguaje de definición de datos (DDL)
  • Lenguaje de manipulación de datos (DML)
  • Lenguaje de consulta de datos (DQL)
  • Consultas complejas

DML – INSERT INTO

-- Tres valores correctos
INSERT INTO Departamentos (nombreDep, localidad) VALUES ('Historia', NULL);
INSERT INTO Departamentos (nombreDep, localidad) VALUES ('Informática', 'Sevilla');
INSERT INTO Departamentos (nombreDep, localidad) VALUES ('Arte', 'Cádiz');
-- Valores repetidos
-- Esta tupla se inserta dos veces !!
INSERT INTO Departamentos (nombreDep, localidad) VALUES ('Historia', NULL); 
-- Esta no
INSERT INTO Departamentos (nombreDep, localidad) VALUES ('Informática', 'Sevilla'); 

DML – INSERT INTO

-- Pedro de Historia 
INSERT INTO Empleados(departamentoId, jefe, nombre, salario, fechaInicial, fechaFinal, comision)
   VALUES (1, NULL, 'Pedro', 2300.00, '2017-09-15', NULL, 0.2);
-- José de Historia
INSERT INTO Empleados(departamentoId, jefe, nombre, salario, fechaInicial, fechaFinal, comision)
   VALUES (1, NULL, 'José', 2500.00, '2018-08-15', NULL, 0.5);
-- Lola de Informática 
INSERT INTO Empleados(departamentoId, jefe, nombre, salario, fechaInicial, fechaFinal, comision)
   VALUES (2, NULL, 'Lola', 2300.00, '2018-08-15', NULL, 0.3);
-- Luis trabajó para Pedro 3 meses 
INSERT INTO Empleados(departamentoId, jefe, nombre, salario, fechaInicial, fechaFinal, comision)
   VALUES (1, 1, 'Luis', 1300.00, '2018-08-15', '2018-11-15', 0);
-- Ana trabajó para Pedro 3 meses 
INSERT INTO Empleados(departamentoId, jefe, nombre, salario, fechaInicial, fechaFinal, comision)
   VALUES (1, 1, 'Ana', 1300.00, '2018-08-15', '2018-11-15', 0);

DML – INSERT INTO

-- Manuel de Electrónica 
INSERT INTO Empleados(departamentoId, jefe, nombre, 
   salario, fechaInicial, fechaFinal, comision)
VALUES (5, null, 'Manuel', 
   2300.00, '2017-08-15', NULL, 0.6);

El departamendo 5 no existe

-- Francisco trabajo para Yolanda 
INSERT INTO Empleados(departamentoId, jefe, nombre, 
   salario, fechaInicial, fechaFinal, comision)
VALUES (1, 23, 'Francisco', 
   1300.00, '2017-08-15', '2017-11-15', 0);

El empleado 23 no existe

DML - UPDATE

-- Subir el sueldo de Pedro 
UPDATE Empleados SET salario='2500.00' WHERE  empleadoId=1;
-- Despedir a José 
UPDATE Empleados SET fechaFinal='2019-08-15' WHERE empleadoId=2;

DML - UPDATE

UPDATE Departamentos SET localidad='Sevilla' WHERE  departamentoId=4;

DML - DELETE

CREATE TABLE Empleados ...
FOREIGN KEY(departamentoId) REFERENCES Departamentos(departamentoId)
   ON DELETE SET NULL,
FOREIGN KEY(jefe) REFERENCES Empleados(empleadoId)
...
-- Borrar departamento de Historia 
DELETE FROM Departamentos WHERE  departamentoId=1;

DML - DELETE

FOREIGN KEY(departamentoId) REFERENCES Departamentos(departamentoId)
   ON DELETE CASCADE,
FOREIGN KEY(jefe) REFERENCES Empleados(empleadoId)
   ON DELETE CASCADE,
...
-- Borrar departamento de Historia 
DELETE FROM Departamentos WHERE  departamentoId=1;

DML - DELETE

FOREIGN KEY(departamentoId) REFERENCES Departamentos(departamentoId) 
   ON DELETE CASCADE,
FOREIGN KEY(jefe) REFERENCES Empleados(empleadoId),
-- Borrar departamento de Historia 
DELETE FROM Departamentos WHERE  departamentoId=1;

Inyecciones SQL

¡Ojo con insertar texto suministrado por el usuario directamente en una sentencia SQL!

query = "INSERT INTO Multas VALUES (" + matricula + ")"

Contenido

  • Introducción
  • Lenguaje de definición de datos (DDL)
  • Lenguaje de manipulación de datos (DML)
  • Lenguaje de consulta de datos (DQL)
  • Consultas complejas

DQL – SELECT

Πcolumnas(σcondicioˊn(T1×T2××Tn))\Proj_{columnas} \left(\Sel_{condición}(T_1 \times T_2 \times \dots \times T_n)\right)

SELECT < lista de columnas >
	FROM    < T1, T2,.. ,Tn >
	WHERE  < condición >

Πnombre,salario(σsalario<2000(Empleados))\Proj_{nombre,salario} \left(\Sel_{salario < 2000}(Empleados)\right)

SELECT nombre, salario
FROM Empleados
WHERE salario < 2000;

σsalario<2000(Empleados)\Sel_{salario < 2000}(Empleados)

SELECT *
FROM Empleados
WHERE salario < 2000;

DQL – SELECT DISTINCT

SELECT ALL fechaInicial, fechaFinal
FROM Empleados;

SELECT DISTINCT fechaInicial, fechaFinal
FROM Empleados;

DQL – SELECT

La cláusula WHERE puede estar formada por:

  • Una combinación de AND, OR y NOT
  • Operador EXISTS
  • Operador IN
  • Operadores ALL, ANY o SOME
  • Operadores BETWEEN, UNIQUE, TOP, IS NULL, LIKE

DQL - SELECT

https://mariadb.com/kb/en/library/select/

DQL – SELECT (renombrado)

Para compactar las expresiones en AR podemos usar el operador de renombrado ρ\rho, por ejemplo:

ρE(eId,dId,jId,n,s,fi,ff,c)(Empleados)\Ren_{E(eId, dId, jId, n, s, fi, ff, c)} (Empleados)

ρD(dId,n,l)(Departamentos)\Ren_{D(dId, n, l)} (Departamentos)

Una vez renombradas las relaciones se puede hacer referencia al nombre de los empleados en lugar de Empleados.nombreEmpleados.nombre podemos escribir E.nE.n.

DQL – SELECT (BETWEEN)

Πn,s(σs2000s3000(E))\Proj_{n,s}\left(\Sel_{s\ge2000 \land s\le3000}(E)\right)

-- Con DISTINCT nos aseguramos que no  haya duplicados en el resultado
SELECT DISTINCT nombre, salario
FROM Empleados
WHERE salario >=2000 AND salario <=3000;
-- equivalente
SELECT DISTINCT nombre, salario
FROM Empleados
WHERE salario BETWEEN 2000 AND 3000
;

DQL – SELECT (IN)

Permite comparar un valor individual vv (un nombre de atributo) con un conjunto de valores VV (generalmente una consulta anidada). Devuelve TRUE si vv es uno de los elementos de VV.

Πn,s(σs=1000s=2000s=3000(E))\Proj_{n,s}\left(\Sel_{s=1000 \lor s=2000 \lor s=3000}(E)\right)

SELECT DISTINCT nombre, salario
FROM Empleados
WHERE salario IN (1000, 2500, 3000);

DQL – SELECT (LIKE)

Para comparar cadenas de caracteres se utiliza el operador de comparación LIKE.
Las cadenas parciales se especifican mediante los caracteres reservados % y _:

  • % representa cualquier cadena de caracteres
  • _ representa un único carácter

DQL – SELECT (LIKE)

-- Empleados con una 'o' en la segunda posición de su nombre
o que son jefes 
SELECT *
FROM Empleados
WHERE nombre LIKE '_o%' OR jefe IS NULL;

En AR no hay expresión equivalente

DQL – SELECT (ORDER BY)

-- Ordena por departamento descendente y a 
-- igual departamento por nombre del empleado alfabético

SELECT *
FROM Empleados
ORDER BY departamentoId, nombre;

En AR no se puede definir orden, son conjuntos

DQL – SELECT (producto cartesiano)

El producto cartesiano devuelve una nueva relación con todas las posibles combinaciones entre las tuplas de las relaciones involucradas.

SELECT *
FROM Empleados, Departamentos;

Empleados×DepartamentosEmpleados \times Departamentos

DQL – SELECT (NATURAL JOIN)

ΠE.n,E.s,E.fi,D.n(σD.did=E.dId(E×D))\Proj_{E.n, E.s, E.fi, D.n}\left(\Sel_{D.did=E.dId}(E \times D)\right)

SELECT nombre n, salario s, fechaInicial fi, nombreDep nd
FROM Empleados E, Departamentos D
WHERE E.departamentoId=D.departamentoId;

ΠE.n,E.s,E.fi,D.n(ED)\Proj_{E.n, E.s, E.fi, D.n}(E \bowtie D)

SELECT nombre, salario, fechaInicial, nombreDep
FROM Empleados NATURAL JOIN Departamentos;

DQL – SELECT (LEFT/RIGHT JOIN)

T1 RIGHT/LEFT JOINT T2 ON <cond> devuelve todas las filas de la tabla derecha/izquierda, y todas las filas que cumplen de la tabla de la izquierda/derecha que cumplen la condición.

UPDATE Empleados SET departamentoId=NULL WHERE empleadoId=5;
SELECT nombre, salario, fechaInicial, nombreDep
FROM Empleados E LEFT/RIGHT JOIN Departamentos D ON E.departamentoId=D.departamentoId;

En AR no vamos a usar estos operadores

DQL – SELECT (UNION)

SELECT *
FROM Empleados E
   LEFT JOIN Departamentos D
   ON E.departamentoId=D.departamentoId
UNION
SELECT *
FROM Empleados E
  RIGHT JOIN Departamentos D
  ON E.departamentoId=D.departamentoId;

El conjunto de tuplas resultado contiene el “join” de todos empleados (aunque no estén en un departamento) con todos los departamentos (aunque no tengan ningún empleado)

DQL – SELECT (EXISTS)

-- Departamentos sin Empleados 
SELECT *
FROM Departamentos D
WHERE NOT EXISTS (
SELECT * FROM Empleados E
WHERE D.departamentoId=E.departamentoId
);

-- Departamentos con Empleados 
SELECT *
FROM Departamentos D
WHERE EXISTS (
SELECT * FROM Empleados E
WHERE D.departamentoId=E.departamentoId
);

DΠD.dId,D.n,D.l(DE)D \setminus \Proj_{D.dId, D.n, D.l}(D \NatJoin E)

Contenido

  • Introducción
  • Lenguaje de definición de datos (DDL)
  • Lenguaje de manipulación de datos (DML)
  • Lenguaje de consulta de datos (DQL)
  • Consultas complejas

Consultas complejas

Están enfocadas a los niveles táctico y estratégico de un sistema de información.
Presentan los datos agrupados a partir de los registros individuales que corresponden a las operaciones diarias

Consultas complejas (Agregados)

Funciones agregadas

  • COUNT devuelve el número de filas o valores especificados en una consulta.
  • SUM, MAX, MIN, AVG se aplican a un conjunto o multiconjunto de valores numéricos y devuelven respectivamente la suma, el valor máximo, el mínimo y el promedio de dichos valores.
  • Estas funciones se pueden usar con la cláusula SELECT o con la cláusula HAVING.

Consultas complejas (GROUP BY)

GROUP BY

  • Agrupa las tuplas que tienen el mismo valor para ciertos atributos
  • Permite aplicar las funciones de agregación a cada uno de esos grupos (countcount, sumsum, maxmax, minmin, avgavg, ...).
  • Los atributos de agrupacion pueden aparecer en la cláusula SELECT.
  • Equivalente en AR:

    Υagrupadoragrupador,funciones\Group_{agrupador}^{agrupador, funciones}

Consultas complejas (Agregados)

-- Estadísticas salarios de los empleados 
SELECT COUNT(*), MIN(salario), MAX(salario), AVG(salario), SUM(salario)
FROM Empleados;

Υcount(),min(s),avg(s),sum(s)(E)\Group^{count(*), min(s), avg(s), sum(s)}(E)

Esta consulta al no agrupar por ningún atributo las funciones de agregación se aplican a toda la columna.

Consultas complejas (GROUP BY)

Calcular para cada departamento el número de empleados, el salario medio de los mismos, el salario con las comisiones, y el gasto total en salarios

SELECT departamentoId, COUNT(*), AVG(salario) salarioMedio, 
   AVG(salario * (1+comision)) salarioConComision, SUM(salario) gastoSalarios
FROM Empleados
GROUP BY departamentoId;

ΥE.dIdE.dId,count(),avg(s),avg(s(1+c)),sum(s)(E)\Group_{E.dId}^{E.dId, count(*), avg(s), avg(s*(1+c)), sum(s)} (E)

Consultas complejas (HAVING)

HAVING

  • Especifica una condición sobre el grupo de tuplas asociado a cada valor de los atributos de agrupación (clases de equivalencia).
  • Sólo los grupos que cumplan la condición entrarán en el resultado de la consulta.
  • Primero se filtran las filas mediante WHERE, luego se agrupan, y luego se filtran los grupos mediante HAVING

Consultas complejas (HAVING)

Calcular para cada departamento con más de un empleado, el salario medio de los mismos, el salario con las comisiones, y el gasto total en salarios

SELECT departamentoId, COUNT(*), AVG(salario) salarioMedio,
   AVG(salario * (1+comision)) salarioConComision, SUM(salario) gastoSalarios
FROM Empleados
GROUP BY departamentoId HAVING COUNT(*)>1;

Consultas complejas (HAVING)

-- Consulta equivalente sin HAVING
SELECT * 
FROM (
   SELECT departamentoId, COUNT(*) numEmpleados, AVG(salario) salarioMedio,
      AVG(salario * (1+comision)) salarioConComision, SUM(salario) gastoSalarios
   FROM Empleados
   GROUP BY departamentoId
   ) Estadistica
WHERE numEmpleados>1;

σn>1(ΥE.dIdE.dId,ρncount(),avg(s),avg(s(1+c)),sum(s)(E))\Sel_{n > 1}\left(\Group_{E.dId}^{E.dId, \Ren_{n}count(*), avg(s), avg(s * (1+c)), sum(s)}(E)\right)

Consultas complejas (ALL, ANY)

Permite comparar un valor individual vv (nombre de atributo) con un conjunto de valores VV (consulta anidada).

Ejemplo: empleados con salario mayor que el salario medio en todos los departamentos.

SELECT * FROM Empleados
WHERE salario >
ALL (SELECT AVG(salario)
       FROM Empleados
       GROUP BY departamentoId);

σs>m(Υρm(max(avg(s)))(ΥE.dIdavg(s)(E)))\Sel_{s>m}\left(\Group^{\Ren_{m}(max(avg(s)))}\left(\Group_{E.dId}^{avg(s)}(E)\right)\right)

Consultas complejas (ALL, ANY)

-- Departamento con más empleados 
-- Opción 1 
SELECT departamentoId FROM Empleados
GROUP BY departamentoId HAVING COUNT(*)>= ALL
   ( SELECT COUNT(*)
     FROM Empleados
     GROUP BY departamentoId    );
-- Opción 2 
SELECT departamentoId FROM Empleados
GROUP BY departamentoId HAVING COUNT(*) =
   ( SELECT MAX(total) FROM
      ( SELECT COUNT(*) AS total
        FROM Empleados
        GROUP BY departamentoId
       ) NumEmpleados    );

numMaxΥmax(count())(ΥE.dIdcount()(E))numMax \leftarrow \Group^{max(count(*))}\left(\Group_{E.dId}^{count(*)}(E)\right)

σn=numMax(ΥE.dIdρncount()(E))\Sel_{n=numMax}\left(\Group_{E.dId}^{\Ren_{n}count(*)}(E)\right)

Consultas complejas. Views

CREATE OR REPLACE VIEW [vista] AS [SELECT…]

  • Crea una nueva tabla con nombre “vista”, cuyo contenido es el de la consulta
  • Mejora el tiempo de CPU
  • Optimiza el espacio de almacenamiento
-- Vista con las estadísticas de los Empleados por Departamento 
CREATE OR REPLACE VIEW EstadísticasEmpleados AS
SELECT departamentoId,
COUNT(*) AS numEmpleados,
AVG(salario) salarioMedio,
AVG(salario * (1+comision)) salarioConComision,
SUM(salario) gastoSalarios
FROM Empleados
GROUP BY departamentoId;
-- Número de empleados que tiene el departamento con más empleados 
SELECT MAX(numEmpleados)
FROM EstadísticasEmpleados;

MariaDB Error Codes

https://mariadb.com/kb/en/library/mariadb-error-codes/

Retos HackerRank

https://www.hackerrank.com/domains/sql

Conclusiones

SQL (Structured Query Language) es el lenguaje estándar para gestionar bases de datos relacionales, permitiendo crear esquemas (DDL), manipular datos (DML) y controlar acceso (DCL). Su popularidad se debe a su sintaxis intuitiva basada en el lenguaje natural, siendo accesible para analistas y programadores.

El DDL (Data Definition Language) incluye CREATE, ALTER y DROP para definir estructuras: tablas, índices, vistas y restricciones. La transformación del modelo relacional a SQL es directa, con tipos de datos específicos para cada atributo y restricciones que garantizan integridad.

El DML (Data Manipulation Language) incluye SELECT (consultas), INSERT (inserción), UPDATE (actualización) y DELETE (eliminación). La cláusula WHERE filtra datos, JOIN combina tablas, y subconsultas permiten consultas complejas anidadas. El ORDER BY y GROUP BY organizan y agrupan resultados.

Las vistas ofrecen una capa de abstracción, presentando al usuario un subconjunto lógico de datos sin exponer la estructura interna. Los índices mejoran rendimiento de búsquedas a costa de almacenamiento y tiempo de actualización. Las restricciones (PRIMARY KEY, FOREIGN KEY, CHECK, UNIQUE) garantizan integridad.

SQL es únicamente de lectura y modificación; lógica procedural requiere lenguajes de extensión específicos (PL/SQL, T-SQL, PL/pgSQL). La optimización de consultas es un art que requiere comprensión de índices, planes de ejecución y estadísticas de la base de datos. Dominar SQL es fundamental para cualquier profesional que trabaje con datos.

Gracias

Universidad de Sevilla

Departamento de Lenguajes y Sistemas Informáticos

![](./images/dml-delete-07.png)