├── .gitignore ├── 0. Entorno.md ├── 1. Sentencias DDL.md ├── 2. Sentencias DML.md ├── Recursos y extensiones.md ├── sesion1.sql ├── sesion2-dml.sql ├── sesion2-pagila.sql ├── sesion3-concesionario.sql ├── sesion4-consultas.sql └── sesion5-optimizacion.sql /.gitignore: -------------------------------------------------------------------------------- 1 | .obsidian -------------------------------------------------------------------------------- /0. Entorno.md: -------------------------------------------------------------------------------- 1 | 2 | ## PostgreSQL 3 | Enlace de [descarga](https://www.enterprisedb.com/downloads/postgres-postgresql-downloads). 4 | 5 | Puerto por defecto ``5432``. 6 | 7 | Incorpora el programa [pgAdmin](https://www.pgadmin.org/download/). 8 | 9 | ## MySQL 10 | Enlace de [descarga](https://dev.mysql.com/downloads/windows/installer/8.0.html). 11 | 12 | Puerto por defecto ``3306``. 13 | 14 | Descargar MySQL Installer, ejecutar y seleccionar instalación completa para que instale: 15 | 16 | * MySQL Community Server 17 | * [MySQL Workbench](https://www.mysql.com/products/workbench/) 18 | 19 | ## Herramientas GUI 20 | * [pgAdmin](https://www.pgadmin.org/download/) 21 | * [MySQL Workbench](https://www.mysql.com/products/workbench/) 22 | * [DBeaver](https://dbeaver.io/) 23 | * [DataGrip](https://www.jetbrains.com/datagrip/) 24 | 25 | ## Conexión a bases de datos 26 | 27 | * **PostgreSQL**: abrir pgAdmin y crear nuevo servidor para conectarse con usuario: 28 | * usuario: ``postgres`` 29 | * password: ``admin`` 30 | * **MySQL Workbench**: Crear nueva conexión con los datos: 31 | * usuario: ``root`` 32 | * password: ``admin`` 33 | 34 | ## Bases de datos de prueba 35 | 36 | Para PostgreSQL: 37 | 38 | * [pagila](https://github.com/devrimgunduz/pagila) 39 | 40 | 41 | ### Cargar base de datos pagila (PostgreSQL) 42 | 43 | Crear base de datos pagila: 44 | 45 | ```sql 46 | CREATE DATABASE pagila 47 | ``` 48 | 49 | En la cmd ejecutar el sql para **crear el esquema**: 50 | 51 | ``` 52 | psql -h localhost -p 5432 -U postgres -d pagila < pagila-schema.sql 53 | ``` 54 | 55 | 56 | En la cmd ejecutar el sql para **poblar el esquema**: 57 | 58 | ``` 59 | psql -h localhost -p 5432 -U postgres -d pagila < pagila-data.sql 60 | ``` -------------------------------------------------------------------------------- /1. Sentencias DDL.md: -------------------------------------------------------------------------------- 1 | ## Sentencias DDL 2 | Data Definition Language 3 | 4 | 5 | Operaciones con **Bases de datos**: 6 | 7 | * Crear base de datos: ``CREATE DATABASE employees2;`` 8 | * Borrar una base de datos: ``DROP DATABASE employees2;`` 9 | 10 | 11 | Operaciones con **Tablas**: 12 | 13 | * Crear tablas: ``CREATE TABLE IF NOT EXISTS employees (...);`` 14 | * Borrar tablas: ``DROP TABLE IF EXISTS employees;`` 15 | * Cambiar el nombre de una tabla: 16 | * ``ALTER TABLE IF EXISTS employees RENAME TO employees_2021;`` 17 | * Agregar columnas a una tabla: 18 | * ``ALTER TABLE employees ADD COLUMN email VARCHAR(100);`` 19 | * Borrar columnas de una tabla: 20 | * ``ALTER TABLE employees DROP COLUMN IF EXISTS salary;`` 21 | 22 | 23 | **Tipos de datos** en tablas: 24 | 25 | * ``INT`` 26 | * ``BOOLEAN`` 27 | * ``CHAR``, ``VARCHAR``, ``TEXT`` 28 | * ``NUMERIC`` 29 | * ``DATE`` 30 | * ``TIME`` 31 | * ``SERIAL`` 32 | 33 | **Restricciones** en las columnas de las tablas: 34 | 35 | * ``PRIMARY KEY`` 36 | * ``NOT NULL`` 37 | * ``UNIQUE`` 38 | * ``CHECK`` -------------------------------------------------------------------------------- /2. Sentencias DML.md: -------------------------------------------------------------------------------- 1 | ## Sentencias DML 2 | Data Manipulation Language 3 | 4 | Operaciones **CRUD**: 5 | 6 | * ==C==: Create --> ``INSERT INTO`` 7 | * ==R==: Retrieve o Read --> ``SELECT FROM`` 8 | * ==U==: Update --> ``UPDATE`` 9 | * ==D==: Delete --> ``DELETE FROM`` 10 | 11 | 12 | ### 1. Recuperar datos (SELECT) 13 | 14 | Recuperar todos los empleados: 15 | 16 | ```sql 17 | SELECT * FROM employees; 18 | ``` 19 | 20 | 21 | ### 2. Insertar nuevos datos (INSERT) 22 | 23 | Insertar un nuevo empleado: 24 | 25 | ```sql 26 | INSERT INTO employees (married, name, email, genre, salary, birth_date, start_at) VALUES (TRUE, 'Employee2', 'employee1@company.com', 'M', 29567.23, '1990-12-25', '08:30:00'); 27 | ``` 28 | 29 | ### 3. Actualizar datos (UPDATE) 30 | 31 | 32 | ### 4. Borrar datos (DELETE) -------------------------------------------------------------------------------- /Recursos y extensiones.md: -------------------------------------------------------------------------------- 1 | ## Material PostgreSQL 2 | 3 | [Awesome PostgreSQL](https://github.com/dhamaniasad/awesome-postgres) 4 | 5 | [PostGIS](https://postgis.net/) 6 | 7 | -------------------------------------------------------------------------------- /sesion1.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE pagila; 2 | DROP DATABASE pagila; 3 | 4 | 5 | -- Creación de tablas 6 | CREATE TABLE IF NOT EXISTS employees( 7 | id INT 8 | ); 9 | 10 | -- ver datos de una tabla 11 | SELECT * FROM employees; 12 | 13 | -- Tipos de datos: boolean 14 | CREATE TABLE IF NOT EXISTS employees( 15 | id INT, 16 | married BOOLEAN 17 | ); 18 | 19 | -- Insertar datos 20 | INSERT INTO employees (id, married) VALUES (1, TRUE); 21 | INSERT INTO employees (id, married) VALUES (2, FALSE); 22 | 23 | -- Tipos de datos: CHAR, VARCHAR, TEXT 24 | CREATE TABLE IF NOT EXISTS employees( 25 | id INT, 26 | married BOOLEAN, 27 | name VARCHAR(250), 28 | genre CHAR(1) 29 | ); 30 | 31 | INSERT INTO employees (id, married, name, genre) VALUES (1, TRUE, 'Juan', 'M'); 32 | 33 | -- Tipo de datos: NUMERIC 34 | CREATE TABLE IF NOT EXISTS employees( 35 | id INT, 36 | married BOOLEAN, 37 | name VARCHAR(250), 38 | genre CHAR(1), 39 | salary NUMERIC(9,2) 40 | ); 41 | INSERT INTO employees (id, married, name, genre, salary) VALUES (1, TRUE, 'Juan', 'M', 29567.23); 42 | 43 | 44 | -- Tipo de dato: DATE 45 | CREATE TABLE IF NOT EXISTS employees( 46 | id INT, 47 | married BOOLEAN, 48 | name VARCHAR(250), 49 | genre CHAR(1), 50 | salary NUMERIC(9,2), 51 | birth_date DATE 52 | ); 53 | INSERT INTO employees (id, married, name, genre, salary, birth_date) VALUES (1, TRUE, 'Juan', 'M', 29567.23, '1990-12-25'); 54 | 55 | -- Tipo de dato: TIME 56 | CREATE TABLE IF NOT EXISTS employees( 57 | id INT, 58 | married BOOLEAN, 59 | name VARCHAR(250), 60 | genre CHAR(1), 61 | salary NUMERIC(9,2), 62 | birth_date DATE, 63 | start_at TIME 64 | ); 65 | INSERT INTO employees (id, married, name, genre, salary, birth_date, start_at) 66 | VALUES (1, TRUE, 'Juan', 'M', 29567.23, '1990-12-25', '08:30:00'); 67 | 68 | -- Identificador 69 | CREATE TABLE IF NOT EXISTS employees( 70 | id SERIAL, 71 | married BOOLEAN, 72 | name VARCHAR(250), 73 | genre CHAR(1), 74 | salary NUMERIC(9,2), 75 | birth_date DATE, 76 | start_at TIME 77 | ); 78 | INSERT INTO employees (married, name, genre, salary, birth_date, start_at) 79 | VALUES (TRUE, 'Antonio', 'M', 29567.23, '1990-12-25', '08:30:00'); 80 | 81 | -- verificar que todavía sigue permitiendo insertar un id duplicado 82 | INSERT INTO employees (id, married, name, genre, salary, birth_date, start_at) 83 | VALUES (1, TRUE, 'Antonio', 'M', 29567.23, '1990-12-25', '08:30:00'); 84 | 85 | -- Primary Key 86 | CREATE TABLE IF NOT EXISTS employees( 87 | id SERIAL PRIMARY KEY, 88 | married BOOLEAN, 89 | name VARCHAR(250), 90 | genre CHAR(1), 91 | salary NUMERIC(9,2), 92 | birth_date DATE, 93 | start_at TIME 94 | ); 95 | 96 | INSERT INTO employees (married, name, genre, salary, birth_date, start_at) 97 | VALUES (TRUE, 'Antonio', 'M', 29567.23, '1990-12-25', '08:30:00'); 98 | 99 | -- verificar que ya no permite insertar id duplicado 100 | INSERT INTO employees (id, married, name, genre, salary, birth_date, start_at) 101 | VALUES (1, TRUE, 'Antonio', 'M', 29567.23, '1990-12-25', '08:30:00'); 102 | 103 | -- Hacer que un campo sea obligatorio con NOT NULL 104 | CREATE TABLE IF NOT EXISTS employees( 105 | id SERIAL PRIMARY KEY, 106 | married BOOLEAN, 107 | name VARCHAR(250) NOT NULL, 108 | genre CHAR(1), 109 | salary NUMERIC(9,2), 110 | birth_date DATE, 111 | start_at TIME 112 | ); 113 | 114 | -- Comprobar que no deja insertar el empleado sin ponerle un name 115 | INSERT INTO employees (married, genre, salary, birth_date, start_at) 116 | VALUES (TRUE, 'M', 29567.23, '1990-12-25', '08:30:00'); 117 | 118 | -- Hacer que un campo sea único con UNIQUE 119 | CREATE TABLE IF NOT EXISTS employees( 120 | id SERIAL PRIMARY KEY, 121 | married BOOLEAN, 122 | name VARCHAR(250) NOT NULL, 123 | email VARCHAR(100) UNIQUE, 124 | genre CHAR(1), 125 | salary NUMERIC(9,2), 126 | birth_date DATE, 127 | start_at TIME 128 | ); 129 | INSERT INTO employees (married, name, email, genre, salary, birth_date, start_at) 130 | VALUES (TRUE, 'Employee1', 'employee1@company.com', 'M', 29567.23, '1990-12-25', '08:30:00'); 131 | 132 | -- Verificar que da fallo por email repetido debería ser único 133 | INSERT INTO employees (married, name, email, genre, salary, birth_date, start_at) 134 | VALUES (TRUE, 'Employee2', 'employee1@company.com', 'M', 29567.23, '1990-12-25', '08:30:00'); 135 | 136 | SELECT * FROM employees; 137 | 138 | -- Restricciones en rangos de datos CHECK 139 | CREATE TABLE IF NOT EXISTS employees( 140 | id SERIAL PRIMARY KEY, 141 | married BOOLEAN, 142 | name VARCHAR(250) NOT NULL, 143 | email VARCHAR(100) UNIQUE, 144 | genre CHAR(1), 145 | salary NUMERIC(9,2) CHECK (salary >= 15000), 146 | birth_date DATE CHECK (birth_date > '1975-01-01'), 147 | start_at TIME 148 | ); 149 | 150 | INSERT INTO employees (married, name, email, genre, salary, birth_date, start_at) 151 | VALUES (TRUE, 'Employee1', 'employee1@company.com', 'M', -1, '1990-12-25', '08:30:00'); 152 | 153 | INSERT INTO employees (married, name, email, genre, salary, birth_date, start_at) 154 | VALUES (TRUE, 'Employee1', 'employee2@company.com', 'M', 16000, '1960-12-25', '08:30:00'); 155 | 156 | 157 | -- Renombrar tabla 158 | ALTER TABLE IF EXISTS employees RENAME TO employees_2021; 159 | 160 | -- Agregar columnas a las tablas 161 | ALTER TABLE employees ADD COLUMN email VARCHAR(100); 162 | 163 | -- Borrar columnas de una tabla 164 | ALTER TABLE employees DROP COLUMN IF EXISTS salary; 165 | 166 | -- Borrar tabla 167 | DROP TABLE IF EXISTS employees; -------------------------------------------------------------------------------- /sesion2-dml.sql: -------------------------------------------------------------------------------- 1 | /* Sentencias DML: Data Manipulation Language 2 | CRUD: 3 | 4 | Create (INSERT INTO) 5 | Read (SELECT FROM), 6 | Update (UPDATE SET) 7 | Delete (DELETE FROM) 8 | */ 9 | 10 | -- 1. Consultas o recuperación de datos 11 | 12 | SELECT * FROM employees; 13 | 14 | SELECT id FROM employees; 15 | 16 | SELECT id, email FROM employees; 17 | 18 | SELECT email, id FROM employees; 19 | 20 | SELECT id, email, salary FROM employees; 21 | 22 | -- Filtrar filas 23 | SELECT * FROM employees WHERE id = 1; 24 | 25 | SELECT * FROM employees WHERE name = 'Employee1'; 26 | 27 | SELECT * FROM employees WHERE married = 'true'; 28 | 29 | SELECT * FROM employees WHERE married = TRUE; 30 | 31 | SELECT * FROM employees WHERE birth_date = '1990-12-25'; 32 | 33 | SELECT * FROM employees WHERE married = TRUE AND salary > 10000; 34 | 35 | 36 | -- 2. Inserción de datos 37 | 38 | INSERT INTO employees(name, email) VALUES ('Juan', 'juan@company.com'); 39 | 40 | INSERT INTO employees(name, email, married, genre, salary) 41 | VALUES ('antonio4', 'antonio4@company.com', TRUE, 'M', 23566.43); 42 | 43 | INSERT INTO employees(name, email, married, genre, salary, birth_date, start_at) 44 | VALUES ('francisco', 'francisco@company.com', TRUE, 'M', 23566.43, '1987-5-29', '10:00:00'); 45 | 46 | INSERT INTO employees(name, email, married, genre, salary, birth_date, start_at) 47 | VALUES ('Rosa', 'rosa@company.com', FALSE, 'F', 34543.43, '1990-5-29', '10:00:00'); 48 | 49 | INSERT INTO employees(name, email, married, genre, salary, birth_date, start_at) 50 | VALUES ('Alberto', 'alberto@company.com', FALSE, 'M', 32421.43, '1988-5-29', '10:00:00'); 51 | 52 | INSERT INTO employees 53 | VALUES (9, TRUE, 'francisco3', 'francisco3@company.com', 'M', 23566.43, '1987-5-29', '10:00:00'); 54 | 55 | 56 | -- 3. Actualizar o editar 57 | 58 | UPDATE employees SET birth_date = '2000-03-12'; 59 | 60 | UPDATE employees SET birth_date = '2000-03-12' WHERE id = 5; 61 | 62 | UPDATE employees SET salary = 45000 WHERE email = 'juan@company.com'; 63 | 64 | UPDATE employees SET genre = 'M', start_at = '08:30:00' WHERE email = 'juan@company.com'; 65 | 66 | UPDATE employees SET genre = 'M', start_at = '08:30:00' WHERE email = 'noexiste@company.com'; 67 | 68 | UPDATE employees SET genre = 'M', start_at = '08:30:00' WHERE email = 'juan@company.com' RETURNING *; 69 | 70 | UPDATE employees SET genre = NULL WHERE id = 14; 71 | 72 | -- 4. Borrar 73 | SELECT * FROM employees; 74 | 75 | DELETE FROM employees; 76 | 77 | DELETE FROM employees WHERE married = TRUE; 78 | 79 | DELETE FROM employees WHERE salary < 33000; 80 | 81 | DELETE FROM employees WHERE salary IS NULL; 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /sesion2-pagila.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Explorar tablas 3 | SELECT * FROM actor; 4 | SELECT * FROM actor WHERE last_name = 'WAHLBERG'; 5 | 6 | SELECT * FROM address; 7 | SELECT * FROM address WHERE district = 'California'; 8 | SELECT * FROM address WHERE district = 'California' AND postal_code = '17886'; 9 | SELECT * FROM address WHERE district = 'California' AND postal_code = '17886' OR postal_code = '2299'; 10 | SELECT * FROM address WHERE postal_code = '17886' OR postal_code = '2299'; 11 | 12 | SELECT * FROM category; 13 | SELECT * FROM category WHERE name = 'Action'; 14 | 15 | SELECT * FROM city; 16 | SELECT * FROM city WHERE city = 'Akron'; 17 | SELECT * FROM city WHERE city LIKE 'A%'; 18 | 19 | SELECT * FROM country; 20 | SELECT * FROM country WHERE country = 'Spain'; 21 | 22 | SELECT * FROM customer; 23 | SELECT * FROM customer WHERE last_name = 'WILLIAMS'; 24 | SELECT * FROM customer WHERE activebool = FALSE; 25 | SELECT * FROM customer WHERE activebool = TRUE; 26 | 27 | UPDATE customer SET activebool = FALSE WHERE customer_id = 1; 28 | UPDATE customer SET activebool = TRUE WHERE customer_id = 1; 29 | 30 | SELECT * FROM film; 31 | SELECT * FROM film WHERE description = 'A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies'; 32 | SELECT * FROM film WHERE description LIKE '%Drama%'; 33 | 34 | SELECT * FROM film_actor; 35 | SELECT * FROM film_actor WHERE film_id = 1; 36 | SELECT * FROM film_actor WHERE actor_id = 1; 37 | 38 | SELECT * FROM film_category; 39 | 40 | SELECT * FROM inventory; 41 | 42 | SELECT * FROM language; 43 | SELECT * FROM payment; 44 | SELECT * FROM rental; 45 | SELECT * FROM staff; 46 | SELECT * FROM store; 47 | 48 | -- insertar datos 49 | select * from actor; 50 | 51 | INSERT INTO actor (first_name, last_name) VALUES ('ALAN', 'SASTRE'); 52 | 53 | 54 | select * from customer; 55 | select * from address; 56 | select * from store; 57 | 58 | INSERT INTO address (address, district, city_id, postal_code, phone) 59 | VALUES ('Calle falsa', 'Nueva América', 300, '28004', '12334354352'); 60 | 61 | -- address 606 62 | 63 | INSERT INTO customer(store_id, first_name, last_name, email, address_id, activebool, create_date) 64 | VALUES (1, 'CUSTOMER NEW', 'LASTNAME EXAMPLE', 'customernew@company.com', 606, TRUE, '2021-12-1'); 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /sesion3-concesionario.sql: -------------------------------------------------------------------------------- 1 | -- MANUFACTURER 2 | 3 | CREATE TABLE manufacturer( 4 | id SERIAL, 5 | name VARCHAR(50) NOT NULL, 6 | num_employees INT, 7 | CONSTRAINT pk_manufacturer PRIMARY KEY(id) 8 | ); 9 | 10 | SELECT * FROM manufacturer; 11 | 12 | INSERT INTO manufacturer (name, num_employees) 13 | VALUES ('Ford', 29000); 14 | 15 | INSERT INTO manufacturer (name, num_employees) 16 | VALUES ('Toyota', 45000); 17 | 18 | -- MODEL 19 | 20 | CREATE TABLE model( 21 | id SERIAL, 22 | name VARCHAR(50) NOT NULL, 23 | id_manufacturer INT, 24 | CONSTRAINT pk_model PRIMARY KEY(id), 25 | CONSTRAINT fk_model_manufacturer FOREIGN KEY(id_manufacturer) REFERENCES manufacturer(id) 26 | ); 27 | 28 | SELECT * FROM model; 29 | 30 | INSERT INTO model (name, id_manufacturer) 31 | VALUES ('Mondeo', 1); 32 | 33 | INSERT INTO model (name, id_manufacturer) 34 | VALUES ('Fiesta', 1); 35 | 36 | INSERT INTO model (name, id_manufacturer) 37 | VALUES ('Prius', 2); 38 | 39 | -- VERSION 40 | 41 | CREATE TABLE version( 42 | id SERIAL, 43 | name VARCHAR(50) NOT NULL, 44 | engine VARCHAR(50), 45 | price NUMERIC, 46 | cc NUMERIC(2,1), 47 | id_model INT, 48 | CONSTRAINT pk_version PRIMARY KEY(id), 49 | CONSTRAINT fk_version_model FOREIGN KEY(id_model) REFERENCES model(id) ON UPDATE set null ON DELETE set null 50 | ); 51 | 52 | SELECT * FROM version; 53 | 54 | INSERT INTO version (name, engine, price, cc, id_model) VALUES ('Basic', 'Diesel 4C', 30000, 1.9, 2); 55 | INSERT INTO version (name, engine, price, cc, id_model) VALUES ('Medium', 'Diesel 5C', 50000, 2.2, 2); 56 | INSERT INTO version (name, engine, price, cc, id_model) VALUES ('Advance', 'Diesel 6C V', 80000, 3.2, 2); 57 | 58 | INSERT INTO version (name, engine, price, cc, id_model) VALUES ('Sport', 'Gasolina 4C', 50000, 2.1, 3); 59 | INSERT INTO version (name, engine, price, cc, id_model) VALUES ('Sport advance', 'Gasolina 8C', 90000, 3.2, 3); 60 | 61 | -- EXTRA 62 | CREATE TABLE extra( 63 | id SERIAL, 64 | name VARCHAR(50) NOT NULL, 65 | description VARCHAR(300), 66 | CONSTRAINT pk_extra PRIMARY KEY(id) 67 | ); 68 | 69 | CREATE TABLE extra_version ( 70 | id_version INT, 71 | id_extra INT, 72 | price NUMERIC NOT NULL CHECK (price >= 0), 73 | CONSTRAINT pk_extra_version PRIMARY KEY(id_version, id_extra), 74 | CONSTRAINT fk_version_extra FOREIGN KEY(id_version) REFERENCES version(id) ON UPDATE cascade ON DELETE cascade, 75 | CONSTRAINT fk_extra_version FOREIGN KEY(id_extra) REFERENCES extra(id) ON UPDATE cascade ON DELETE cascade 76 | ); 77 | 78 | INSERT INTO extra (name, description) 79 | VALUES ('Techo solar', 'Techo solar flamante lorem ipsum dolor ...'); 80 | 81 | INSERT INTO extra (name, description) 82 | VALUES ('Climatizador', 'lorem ipsum dolor ...'); 83 | 84 | INSERT INTO extra (name, description) 85 | VALUES ('WiFi', 'lorem ipsum dolor ...'); 86 | 87 | INSERT INTO extra (name, description) 88 | VALUES ('Frigorífico', 'lorem ipsum dolor ...'); 89 | 90 | SELECT * FROM extra; 91 | 92 | SELECT * FROM extra_version; 93 | 94 | -- Ford Mondeo Basic techo solar 95 | INSERT INTO extra_version VALUES (1, 1, 3000); 96 | -- Ford Mondeo Basic climatizador 97 | INSERT INTO extra_version VALUES (1, 2, 1000); 98 | -- Ford Mondeo Basic WiFi 99 | INSERT INTO extra_version VALUES (1, 3, 500); 100 | 101 | -- Ford Mondeo Advance techo solar 102 | INSERT INTO extra_version VALUES (3, 1, 3300); 103 | -- Ford Mondeo Advance climatizador 104 | INSERT INTO extra_version VALUES (3, 2, 1200); 105 | -- Ford Mondeo Advance WiFi 106 | INSERT INTO extra_version VALUES (3, 3, 500); 107 | 108 | CREATE TABLE employee( 109 | id SERIAL, 110 | name VARCHAR(30), 111 | nif VARCHAR(9) NOT NULL UNIQUE, 112 | phone VARCHAR(9), 113 | CONSTRAINT pk_employee PRIMARY KEY(id) 114 | ); 115 | 116 | INSERT INTO employee(name, nif, phone) VALUES('Bob', '123456789', '111111111'); 117 | INSERT INTO employee(name, nif, phone) VALUES('Mike', '123456781', '111111112'); 118 | SELECT * FROM employee; 119 | 120 | CREATE TABLE customer( 121 | id SERIAL, 122 | name VARCHAR(30), 123 | email VARCHAR(50) NOT NULL UNIQUE, 124 | CONSTRAINT pk_customer PRIMARY KEY(id) 125 | ); 126 | 127 | INSERT INTO customer(name, email) VALUES('customer1', 'c1@gmail.com'); 128 | INSERT INTO customer(name, email) VALUES('customer2', 'c2@gmail.com'); 129 | SELECT * FROM customer; 130 | 131 | CREATE TABLE vehicle( 132 | id SERIAL, 133 | license_num VARCHAR (7), 134 | creation_date DATE, 135 | price_gross NUMERIC, 136 | price_net NUMERIC, 137 | type VARCHAR(30), 138 | 139 | id_manufacturer INT, 140 | id_model INT, 141 | id_version INT, 142 | id_extra INT, 143 | 144 | CONSTRAINT pk_vehicle PRIMARY KEY(id), 145 | CONSTRAINT fk_vehicle_manufacturer FOREIGN KEY (id_manufacturer) REFERENCES manufacturer(id), 146 | CONSTRAINT fk_vehicle_model FOREIGN KEY (id_model) REFERENCES model(id), 147 | CONSTRAINT fk_vehicle_extra_version FOREIGN KEY (id_version, id_extra) REFERENCES extra_version(id_version, id_extra) 148 | ); 149 | 150 | SELECT * FROM vehicle; 151 | SELECT * FROM manufacturer; 152 | SELECT * FROM model; 153 | SELECT * FROM extra_version; 154 | SELECT * FROM vehicle; 155 | 156 | INSERT INTO vehicle (license_num, price_gross, id_manufacturer, id_model, id_version, id_extra) 157 | VALUES ('1234LLL', 40000, 1, 2, 1, 2); 158 | 159 | INSERT INTO vehicle (license_num, price_gross, id_manufacturer, id_model, id_version, id_extra) 160 | VALUES ('3456EEE', 60000, 1, 3, 3, 3); 161 | 162 | CREATE TABLE sale( 163 | id SERIAL, 164 | sale_date DATE, 165 | channel VARCHAR(300), 166 | 167 | id_vehicle INT, 168 | id_employee INT, 169 | id_customer INT, 170 | 171 | CONSTRAINT pk_sale PRIMARY KEY(id), 172 | CONSTRAINT fk_sale_vehicle FOREIGN KEY (id_vehicle) REFERENCES vehicle(id), 173 | CONSTRAINT fk_sale_employee FOREIGN KEY (id_employee) REFERENCES employee(id), 174 | CONSTRAINT fk_sale_customer FOREIGN KEY (id_customer) REFERENCES customer(id) 175 | ); 176 | 177 | INSERT INTO sale(sale_date, channel, id_vehicle, id_employee, id_customer) 178 | VALUES('2022-01-01', 'Phone', 1, 1, 1); 179 | 180 | SELECT * FROM sale; -------------------------------------------------------------------------------- /sesion4-consultas.sql: -------------------------------------------------------------------------------- 1 | /* BASE DE DATOS PAGILA */ 2 | 3 | /* 4 | distinct 5 | */ 6 | 7 | -- 604 resultados 8 | select * from address; 9 | 10 | -- 604 resultados 11 | select district from address; 12 | 13 | -- obtener distritos únicos 379 resultados 14 | select distinct district from address; 15 | 16 | -- 600 resultados 17 | select first_name from customer; 18 | 19 | -- 592 resultados 20 | select distinct first_name from customer; 21 | 22 | 23 | /* 24 | and, or, not 25 | order by 26 | 27 | and: se tienen que cumplir si o si las condiciones 28 | or: con que se cumpla una condición es suficiente 29 | not: niega una condición 30 | */ 31 | select * from address where district = 'California'; 32 | select * from address where district != 'California'; 33 | select * from address where not district = 'California'; 34 | select * from address where not district = 'California' order by district; 35 | 36 | select * from address where district = 'Abu Dhabi' or district = 'California'; 37 | 38 | select * from address where district is not null order by district; 39 | select * from address where not district = '' order by district; 40 | 41 | select * from address where address2 is not null and address_id = 1 order by district; 42 | 43 | /* 44 | group by 45 | */ 46 | 47 | select address_id, district from address; 48 | select district, count(district) from address group by district; 49 | select district, count(district) from address group by district order by district; 50 | select district, count(district) as veces from address group by district order by district; 51 | 52 | SELECT * FROM actor; 53 | SELECT last_name, count(last_name) from actor group by last_name; 54 | SELECT last_name, count(last_name) from actor group by last_name HAVING count(last_name) > 1; 55 | 56 | -- obtener en cuantas películas actúa cada actor: 57 | select * from film_actor; 58 | select * from film; 59 | 60 | select f.title, count(fa.actor_id) from film f 61 | inner join film_actor fa on f.film_id = fa.film_id 62 | group by f.title 63 | 64 | -- stock de una película en base a su título 65 | select * from inventory; 66 | 67 | select f.title, count(i.inventory_id) as unidades from film f 68 | inner join inventory i on i.film_id = f.film_id 69 | GROUP BY title; 70 | 71 | select f.title, count(i.inventory_id) as unidades from film f 72 | inner join inventory i on i.film_id = f.film_id 73 | WHERE title = 'FICTION CHRISTMAS' 74 | GROUP BY title; 75 | 76 | select f.title, count(i.inventory_id) as unidades from film f 77 | inner join inventory i on i.film_id = f.film_id 78 | GROUP BY title ORDER BY unidades; 79 | 80 | select f.title, count(i.inventory_id) as unidades from film f 81 | inner join inventory i on i.film_id = f.film_id 82 | GROUP BY title ORDER BY unidades DESC; 83 | 84 | /* 85 | SUM() 86 | */ 87 | select * from customer; 88 | select * from payment; 89 | 90 | SELECT * FROM payment p 91 | inner join customer c on p.customer_id = c.customer_id 92 | 93 | SELECT c.email, count(p.payment_id) as num_pagos FROM payment p 94 | inner join customer c on p.customer_id = c.customer_id 95 | group by c.email 96 | 97 | SELECT c.email, sum(p.amount) as num_pagos FROM payment p 98 | inner join customer c on p.customer_id = c.customer_id 99 | group by c.email 100 | 101 | select * from staff; 102 | 103 | select * from payment p 104 | inner join staff s on p.staff_id = s.staff_id 105 | 106 | select s.first_name, count(p.payment_id) as num_ventas, sum(p.amount) cantidad_ventas from payment p 107 | inner join staff s on p.staff_id = s.staff_id 108 | group by s.first_name 109 | 110 | 111 | -- joins 112 | 113 | select * from customer; 114 | select * from address; 115 | select * from city; 116 | select * from country; 117 | 118 | -- consulta a 2 tablas: customer y address 119 | 120 | select first_name, last_name, customer.address_id from customer 121 | inner join address on customer.address_id = address.address_id 122 | 123 | select * from customer c 124 | inner join address a on c.address_id = a.address_id 125 | 126 | select c.email, a.address from customer c 127 | inner join address a on c.address_id = a.address_id 128 | 129 | -- consulta a 3 tablas: customer, address, city 130 | SELECT * FROM customer cu 131 | INNER JOIN address a ON cu.address_id = a.address_id 132 | INNER JOIN city ci ON a.city_id = ci.city_id 133 | 134 | SELECT cu.email, a.address, ci.city FROM customer cu 135 | INNER JOIN address a ON cu.address_id = a.address_id 136 | INNER JOIN city ci ON a.city_id = ci.city_id 137 | 138 | -- consulta a 4 tablas: customer, address, city, country 139 | SELECT * FROM customer cu 140 | INNER JOIN address a ON cu.address_id = a.address_id 141 | INNER JOIN city ci ON a.city_id = ci.city_id 142 | INNER JOIN country co ON ci.country_id = co.country_id 143 | 144 | SELECT cu.email, a.address, ci.city, co.country FROM customer cu 145 | INNER JOIN address a ON cu.address_id = a.address_id 146 | INNER JOIN city ci ON a.city_id = ci.city_id 147 | INNER JOIN country co ON ci.country_id = co.country_id 148 | 149 | 150 | /* 151 | Función concat() 152 | */ 153 | select * from actor; 154 | 155 | select first_name, last_name from actor; 156 | 157 | select concat(first_name, ' ', last_name) from actor; 158 | 159 | select concat(first_name, ' ', last_name) as full_name from actor; 160 | 161 | /* 162 | LIKE 163 | */ 164 | select * from film; 165 | 166 | SELECT * from film WHERE description LIKE '%Monastery'; 167 | SELECT * from film WHERE description LIKE '%Drama%'; 168 | 169 | select * from actor 170 | 171 | select * from actor where last_name like '%LI%'; 172 | -- Orden ascendente, empieza por el principio y va hasta el final 173 | select * from actor where last_name like '%LI%' order by last_name; 174 | -- Orden descendente, empieza por el final y va hasta el principio 175 | select * from actor where last_name like '%LI%' order by last_name DESC; 176 | 177 | 178 | /* 179 | IN 180 | */ 181 | 182 | select * from country; 183 | 184 | select * from country where country = 'Spain'; 185 | select * from country where country = 'Spain' or country = 'Germany'; 186 | select * from country where country = 'Spain' or country = 'Germany' or country = 'France'; 187 | 188 | SELECT * FROM country WHERE country IN('Spain', 'Germany', 'France', 'Mexico'); 189 | 190 | select * from customer; 191 | 192 | SELECT * FROM customer WHERE customer_id = 15; 193 | 194 | SELECT * FROM customer WHERE customer_id IN(15, 16, 17, 18); 195 | 196 | 197 | /* 198 | Sub queries 199 | */ 200 | 201 | select * from film; 202 | select * from language; 203 | 204 | select distinct language_id from film; 205 | 206 | select * from film f 207 | inner join language l on f.language_id = l.language_id 208 | 209 | select l.name, count(f.film_id) from film f 210 | inner join language l on f.language_id = l.language_id 211 | group by l.name 212 | 213 | -- Cambiar idioma a algunas películas 214 | UPDATE film SET language_id = 2 WHERE film_id > 100 and film_id < 200; 215 | UPDATE film SET language_id = 3 WHERE film_id >= 200 and film_id < 300; 216 | UPDATE film SET language_id = 4 WHERE film_id >= 300 and film_id < 400; 217 | 218 | SELECT title from film 219 | where language_id = (SELECT language_id FROM language WHERE name = 'English') 220 | 221 | SELECT title from film 222 | where language_id IN (SELECT language_id FROM language WHERE name = 'English' or name = 'Italian') 223 | 224 | -- peliculas más alquiladas 225 | 226 | select * from rental; 227 | select * from inventory; 228 | select * from film; 229 | 230 | 231 | SELECT * from film f 232 | inner join (select * from inventory i 233 | inner join rental r on r.inventory_id = i.inventory_id) res on res.film_id = f.film_id 234 | 235 | SELECT f.title, count(f.film_id) as veces_alquilada from film f 236 | inner join (select * from inventory i 237 | inner join rental r on r.inventory_id = i.inventory_id) res on res.film_id = f.film_id 238 | group by f.title 239 | order by veces_alquilada DESC 240 | 241 | 242 | /* BASE DE DATOS concesionario */ 243 | 244 | select * from customer; 245 | select * from employee; 246 | select * from extra; 247 | select * from extra_version; 248 | select * from manufacturer; 249 | select * from model; 250 | select * from sale; 251 | select * from vehicle; 252 | select * from version; 253 | 254 | -- count ventas por empleado 255 | 256 | INSERT INTO sale(sale_date, channel, id_vehicle, id_employee, id_customer) 257 | VALUES('2022-01-01', 'Phone', 1, 1, 1); 258 | 259 | select * from sale s 260 | inner join employee e on s.id_employee = e.id 261 | 262 | select e.name, count(s.id) from sale s 263 | inner join employee e on s.id_employee = e.id 264 | group by e.name 265 | 266 | -- count compras por cliente 267 | select c.email, count(s.id) from sale s 268 | inner join customer c on s.id_customer = c.id 269 | group by c.email 270 | 271 | -- fabricante mas vendido 272 | select * from sale; 273 | select * from vehicle; 274 | select * from manufacturer; 275 | 276 | select * from sale s 277 | inner join vehicle v on s.id_vehicle = v.id 278 | inner join manufacturer m on v.id_manufacturer = m.id 279 | 280 | select m.name, count(s.id) from sale s 281 | inner join vehicle v on s.id_vehicle = v.id 282 | inner join manufacturer m on v.id_manufacturer = m.id 283 | group by m.name 284 | 285 | -- modelo mas vendido 286 | 287 | -- version mas vendido 288 | 289 | -- extra vendido 290 | 291 | -- ventas agrupando por año, mes, dia 292 | -------------------------------------------------------------------------------- /sesion5-optimizacion.sql: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Importar base de datos: 4 | 1 - Crear base de datos northwind desde pgAdmin 5 | 2 - Ejecutar el comando para restaurar la base de datos: 6 | psql -U postgres -d northwind < northwind.sql 7 | */ 8 | 9 | 10 | /* 11 | Consultas de utilidad para explorar y administrar bases de datos y tablas 12 | */ 13 | -- Ver tamaño de las bases de datos 14 | select pg_size_pretty (pg_database_size('northwind')) 15 | select pg_size_pretty (pg_database_size('pagila')) 16 | 17 | select pg_database.datname, pg_size_pretty (pg_database_size(pg_database.datname)) as size FROM pg_database; 18 | 19 | -- ver tamaño de una tabla 20 | select pg_size_pretty(pg_relation_size('orders')) 21 | 22 | -- ver tamaño de las 10 tablas que más ocupan 23 | SELECT 24 | relname AS "relation", 25 | pg_size_pretty ( 26 | pg_total_relation_size (C .oid) 27 | ) AS "total_size" 28 | FROM 29 | pg_class C 30 | LEFT JOIN pg_namespace N ON (N.oid = C .relnamespace) 31 | WHERE 32 | nspname NOT IN ( 33 | 'pg_catalog', 34 | 'information_schema' 35 | ) 36 | AND C .relkind <> 'i' 37 | AND nspname !~ '^pg_toast' 38 | ORDER BY 39 | pg_total_relation_size (C .oid) DESC 40 | LIMIT 10; 41 | 42 | 43 | select current_schema(); 44 | 45 | select * from pg_matviews; 46 | 47 | -- cargar extesiones 48 | CREATE EXTENSION pgcrypto; 49 | 50 | select * from employees 51 | INSERT INTO employees (employee_id, last_name, first_name, notes) VALUES 52 | (11, 'em', 'Emp10', pgp_sym_encrypt('Emp10', 'password')) 53 | 54 | SELECT employee_id, pgp_sym_decrypt(notes::bytea, 'password') as notes from employees; 55 | 56 | 57 | /** 58 | consultas joins 59 | */ 60 | select * from customers; 61 | select * from orders; 62 | select * from shippers; 63 | select * from employees; 64 | 65 | -- 1. INNER JOIN 66 | select o.order_id, c.contact_name from orders o 67 | inner join customers c on o.customer_id = c.customer_id 68 | 69 | select o.order_id, c.contact_name, s.company_name from orders o 70 | inner join customers c on o.customer_id = c.customer_id 71 | inner join shippers s on o.ship_via = s.shipper_id 72 | 73 | -- 2. LEFT JOIN 74 | -- Fijarse en los resultados que aparecen 2 customers al final que no tienen order relacionada: 75 | select c.contact_name, o.order_id from customers c 76 | left join orders o on c.customer_id = o.customer_id 77 | 78 | select c.contact_name, o.order_id from customers c 79 | inner join orders o on c.customer_id = o.customer_id 80 | 81 | 82 | -- 3. RIGHT JOIN 83 | select o.order_id, e.first_name, e.last_name from orders o 84 | inner join employees e on o.employee_id = e.employee_id 85 | -- Fijar que aparecen empleados sin order asociado 86 | select o.order_id, e.first_name, e.last_name from orders o 87 | right join employees e on o.employee_id = e.employee_id 88 | 89 | INSERT INTO employees (employee_id, last_name, first_name, title) VALUES 90 | (10, 'Emp10', 'Emp10', 'Director') 91 | 92 | 93 | -- GROUP BY 94 | select city, count(customer_id) as num_customers from customers group by city; 95 | select city, count(customer_id) as num_customers from customers group by city order by city; 96 | select city, count(customer_id) as num_customers from customers group by city order by num_customers; 97 | select city, count(customer_id) as num_customers from customers group by city order by num_customers desc; 98 | 99 | select country, count(customer_id) as num_customers from customers group by country order by num_customers desc; 100 | 101 | select e.title, count(o.order_id) as num_orders from orders o 102 | inner join employees e on o.employee_id = e.employee_id 103 | group by e.title 104 | order by num_orders desc 105 | 106 | select e.first_name, e.last_name, count(o.order_id) as num_orders from orders o 107 | inner join employees e on o.employee_id = e.employee_id 108 | group by e.first_name, e.last_name 109 | order by num_orders desc 110 | 111 | 112 | /* 113 | vistas 114 | son una forma de guardar las consultas SQL bajo un identificador para ejecutarlas 115 | de manera más sencilla sin tener que repetir todo el código SQL 116 | */ 117 | create view num_orders_by_employee as 118 | select e.first_name, e.last_name, count(o.order_id) as num_orders from orders o 119 | inner join employees e on o.employee_id = e.employee_id 120 | group by e.first_name, e.last_name 121 | order by num_orders desc 122 | 123 | select * from num_orders_by_employee; 124 | 125 | /* 126 | vistas materializadas 127 | 128 | - guardan físicamente el resultado de una query y actualizan los datos periódicamente 129 | - chachean el resultado de una query compleja y permiten refrescarlo 130 | - para crear una vista materializada cargando datos tenemos la opción WITH DATA 131 | 132 | CREATE MATERIALIZED VIEW [IF NOT EXISTS] view_name AS 133 | query 134 | WITH [NO] DATA; 135 | */ 136 | 137 | create materialized view mv_num_orders_by_employee as 138 | select e.first_name, e.last_name, count(o.order_id) as num_orders from orders o 139 | inner join employees e on o.employee_id = e.employee_id 140 | group by e.first_name, e.last_name 141 | order by num_orders desc 142 | with data 143 | 144 | select * from mv_num_orders_by_employee; 145 | 146 | select * from order_details; 147 | 148 | create table example ( 149 | id INT, 150 | name varchar 151 | ) 152 | 153 | /** 154 | generate_series para generar datos de prueba 155 | */ 156 | select * from example 157 | 158 | SELECT * FROM generate_series(1,10); 159 | 160 | INSERT into example(id) 161 | SELECT * FROM generate_series(1, 500000) 162 | 163 | 164 | create materialized view mv_example as 165 | select * from example 166 | with data 167 | 168 | select * from mv_example; 169 | 170 | select * from generate_series( 171 | '2022-01-01 00:00'::timestamp, 172 | '2022-12-25 00:00', 173 | '6 hours' 174 | ) 175 | 176 | /* 177 | EXPLAIN ANALYZE 178 | permite mostrar el query planner y ver los tiempos: 179 | */ 180 | 181 | EXPLAIN ANALYZE select * from order_details where unit_price < 9; 182 | create index idx_order_details_unit_price on order_details(unit_price) where unit_price < 10; 183 | 184 | EXPLAIN ANALYZE select * from num_orders_by_employee; 185 | EXPLAIN ANALYZE select * from orders; 186 | 187 | /* 188 | índices 189 | Estructuras de datos que permiten optimizar las consultas en base a una columna o filtro en particular 190 | con el fin de exitar escaneo secuencial de toda la tabla 191 | */ 192 | create index idx_orders_pk on orders(order_id); 193 | EXPLAIN ANALYZE select * from orders; 194 | 195 | EXPLAIN ANALYZE select * from example; 196 | create index idx_example_pk on example(id); 197 | 198 | EXPLAIN ANALYZE select * from example WHERE id = 456777; 199 | 200 | 201 | /* 202 | Particionamiento de tablas 203 | Técnica que permite dividir una misma tabla en múltiples particiones con el objetivo de optimizar las consultas 204 | 205 | Hay tres tipos: 206 | - Rango 207 | - Lista 208 | - Hash 209 | */ 210 | 211 | 212 | -- Tabla base 213 | CREATE TABLE users ( 214 | id BIGSERIAL, 215 | birth_date DATE NOT NULL, 216 | first_name VARCHAR(20) NOT NULL, 217 | PRIMARY KEY(id, birth_date) 218 | ) PARTITION BY RANGE (birth_date); 219 | 220 | -- particiones 221 | CREATE TABLE users_2020 PARTITION OF users 222 | FOR VALUES FROM ('2020-01-01') TO ('2021-01-01'); 223 | 224 | CREATE TABLE users_2021 PARTITION OF users 225 | FOR VALUES FROM ('2021-01-01') TO ('2022-01-01'); 226 | 227 | CREATE TABLE users_2022 PARTITION OF users 228 | FOR VALUES FROM ('2022-01-01') TO ('2023-01-01'); 229 | 230 | INSERT INTO users(birth_date, first_name) VALUES 231 | ('2020-01-15', 'User 1'), 232 | ('2020-06-15', 'User 2'), 233 | ('2021-02-15', 'User 3'), 234 | ('2021-11-15', 'User 4'), 235 | ('2022-04-15', 'User 5'), 236 | ('2022-12-15', 'User 6'); 237 | 238 | select * from users_2020; 239 | select * from users_2021; 240 | select * from users_2022; 241 | 242 | EXPLAIN ANALYZE select * from users; 243 | EXPLAIN ANALYZE select * from users where birth_date = '2020-06-15'; 244 | EXPLAIN ANALYZE select * from users where birth_date = '2021-02-15'; 245 | EXPLAIN ANALYZE select * from users where birth_date > '2021-02-14' and birth_date < '2022-12-16'; 246 | EXPLAIN ANALYZE select * from users where EXTRACT(month from birth_date) = 6 and EXTRACT(year from birth_date) = 2020 247 | 248 | 249 | 250 | --------------------------------------------------------------------------------