JS, Node.js, Frontend, Backend, Firebase, Express, Patrones, HTML5_APIs, Asincronía, Websockets, Testing
SQL (por sus siglas en inglés Structured Query Language) es un lenguaje declarativo de acceso a bases de datos relacionales que permite especificar diversos tipos de operaciones en ellas. Una de sus características es el manejo del álgebra y el cálculo relacional que permiten efectuar consultas con el fin de recuperar, de forma sencilla, información de bases de datos, así como hacer cambios en ellas. Wikipedia
Lenguaje de definición de datos (DDL)
- creación (CREATE)
- modificación (ALTER)
- borrado (DROP)
componentes principales
- base de datos (DATABASE)
- tablas (TABLE)
- vistas (VIEW)
- índices (INDEX)
- procedimientos almacenados (PROCEDURE)
- disparadores (TRIGGER).
Lenguaje de manipulación de datos (DML)
- consultar (SELECT)
- insertar (INSERT)
- modificar (UPDATE)
- borrar (DELETE)
Lenguaje de control de datos (DCL)
- Confirmar la operacion (COMMIT)
- Retroceder la operacion (ROLLBACK)
- Dar permisos (GRANT)
- Quitar permisos (REVOKE)
Fechas
- DATE format YYYY-MM-DD
- DATETIME format: YYYY-MM-DD HH:MI:SS
- TIMESTAMP format: YYYY-MM-DD HH:MI:SS
- YEAR format YYYY or YY
Numéricos
- TINYINT permite números desde -128 hasta 127
- UNSIGNED los valores posibles empiezan en 0 hasta 255
- SMALLINT permite números desde -32768 hasta 32767
- UNSIGNED los valores posibles empiezan en 0 hasta 65535
- MEDIUMINT permite números desde -8388608 hasta 8388607
- UNSIGNED los valores posibles empiezan en 0 hasta 16777215
- INT permite números desde -2147483648 hasta 2147483647
- UNSIGNED los valores posibles empiezan en 0 hasta 4294967295
- BIGINT permite números desde -9223372036854775808 hasta 9223372036854775807
- UNSIGNED los valores posibles empiezan en 0 hasta 1844674407370955161
- FLOAT Pequeños flotantes
- FLOAT(6,2) tendrá 4 dígitos enteros y 2 decimales, por ejemplo, 5467.67
- DOUBLE permite almacenar grandes números decimales
- DOUBLE(5,1) tendrá 4 dígitos enteros y 1 dígito decimal, por ejemplo, 5467.1
- DECIMAL permite almacenar grandes números decimales de punto fijo, por tanto, los cálculos con este tipo DECIMAL son exactos
- El número máximo de dígitos es de 65
- DECIMAL(20,6) quiere decir que tendrá 14 dígitos enteros y 4 dígitos decimales
Texto
- CHAR sirve para almacenar una cadena de datos de longitud fija
- Longitud máxima 255
- CHAR(50), será un campo de longitud fija de 50 posiciones
- VARCHAR Sirve para almacenar una cadena de datos (caracteres, números y caracteres especiales) de longitud variable
- La longitud máxima es de 255 caracteres
- Hace un buen uso del espacio en disco, porque no reserva el espacio de la longitud máxima definida, si no que solo ocupa espacio el tamaño real de los datos almacenados en ese campo.
- Es el tipo de dato más utilizado para campos pequeños
- TINYTEXT Solo texto
- Máximo 255 carácteres
- TEXT para almacenar una cadena de caracteres de longitud máxima de 65,535 caracteres
- BLOB para almacenar datos de tipo BLOB (Binary Large Object)
- longitud máxima de 65,535 bytes de datos
- MEDIUMTEXT Sirve para almacenar una cadena con una longitud máxima de 16.777.215 caracteres
- MEDIUMBLOB Sirve para almacenar datos tipo BLOB con longitud máxima 16.777.215 bytes
- LONGTEXT Sirve para almacenar una cadena de longitud máxima de 4.294.967.295 caracteres
- LONGBLOB Sirve para almacenar un BLOB de longitud máxima de de 4.294.967.295 byte
- ENUM Sirve para introducir una lista de posibles valores
- La longitud máxima es de 65.535 posibles valores
- Si se intenta introducir un valor en este campo, que no esté incluido en la lista, no se insertará nada y tendrá un valor vacío ('')
- Por ejemplo si definimos una columna como ENUM('uno', 'dos'), entonces en esta columna solo puede almacenar los valores 'uno' o 'dos'.
- SET es similar a ENUM pero la longitud máxima de valores posibles es de 64, y los valores posibles se pueden combinar.
- Por ejemplo, si definimos una columna como SET ('uno', 'dos) entonces esa columna podrá tomar los siguientes valores 'uno' o 'dos' o 'uno,dos', 'dos,uno'.
Crear una base de datos
CREATE DATATABASE mibasedeatos;
Crear una tabla
CREATE TABLE Persons
(
PersonID int,
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
City varchar(255)
);
SELECT - Realizar consultas
- Traer todos los datos de una tabla
SELECT * FROM nombretabla;
- Traer solo alguna columnas de una tabla
SELECT columna1, columna2 FROM nombretabla;
WHERE - Condicciones de filtrado
SELECT * FROM personas
WHERE nombre = 'ANTONIO'
AND OR - Condicciones lógicas
- Sencillas
SELECT * FROM personas
WHERE nombre = 'ANTONIO'
AND apellido1 = 'GARCIA'
- Combinadas
SELECT * FROM personas
WHERE nombre = 'ANTONIO'
AND (apellido1 = 'GARCIA' OR apellido1 = 'LOPEZ')
ORDER BY - Ordenación
- Ascendente
SELECT nombre, apellido1
FROM personas
ORDER BY apellido1 ASC;
- Descendiente
SELECT nombre, apellido1
FROM personas
ORDER BY apellido1 DESC;
Manteniendo el orden de las columnas
INSERT INTO nombre_tabla
VALUES (valor1, valor2, valor3);
Alterando el orden de las columnas
INSERT INTO nombre_tabla (columna1, columna2, columna3,.)
VALUES (valor1, valor2, valor3);
Todas las filas
UPDATE nombre_tabla
SET columna1 = valor1, columna2 = valor2;
Una fila especifica
UPDATE personas
SET apellido2 = 'RODRIGUEZ'
WHERE nombre = 'ANTONIO'
AND apellido1 = 'GARCIA'
AND apellido2 = 'BENITO';
Todas los datos de una tabla
DELETE * FROM nombre_tabla;
Una fila especifica
DELETE FROM personas
WHERE nombre = 'LUIS'
AND apellido1 = 'LOPEZ'
AND apellido2 = 'PEREZ';
Con truncate
TRUNCATE TABLE nombretabla
Índice
ALTER TABLE nombretabla
DROP INDEX nombreindice;
Tabla
DROP TABLE nombretabla;
Base de datos
DROP DATABASE nombrebasededatos;
LIMIT - Limitar la cantidad de resutlados de una consulta
- Traer 2 filas de la tabla
SELECT * FROM personas LIMIT 2;
LIKE Y NOT LIKE - Limitar la cantidad de resutlados a un patrón (Wildcard)
- Aquellos apellidos que contengan "Z"
SELECT * FROM personas
WHERE nombre LIKE '%Z%'; // que contenga una zeta
- Aquellos apellidos que no contengan "le"
SELECT * FROM personas
WHERE nombre NOT LIKE '%le%'; // que contenga una zeta
- Aquellos apellidos que terminen en "l"
SELECT * FROM personas
WHERE nombre LIKE '%l'; // que contenga una zeta
- Aquellas personas cuyo apellido1 empiece por P o G
SELECT * FROM personas
WHERE apellido1 LIKE '[PG]%';
- Aquellas personas cuyo apellido1 tenga PE(x)EZ como PEREZ
SELECT * FROM personas
WHERE apellido1 LIKE 'PE_EZ';
IN - Seleccionar múltiples valores dentro de WHERE
SELECT * FROM personas
WHERE apellido1
IN ('PEREZ','RUIZ');
BETWEEN y NOT BETWEEN - Seleccionar valores entre un rango de datos dentro de WHERE
- Seleccionar personas cuyo apellido1 esté entre 'FERNANDEZ y 'HUERTAS'
SELECT *
FROM personas
WHERE apellido1
BETWEEN 'FERNANDEZ' AND 'HUERTAS';
- Seleccionar personas cuyo apellido1 NO esté entre 'FERNANDEZ y 'HUERTAS'
SELECT *
FROM personas
WHERE apellido1
NOT BETWEEN 'FERNANDEZ' AND 'HUERTAS';
AS - Acortador de nombres
SELECT p.apellido1, p.apellido2
FROM personas
AS p
WHERE p.nombre = 'ANTONIO';
Tipos:
- Interno
- Externo
- Cruzado
Usaremos Northwind database
INNER JOIN
- Juntamos ambas tablas y sustituimos el codigo del departamento por su nombre
- Join por defecto
- Query
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
INNER JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
ORDER BY Customers.CustomerName;
- Ejemplo
- Resultado esperado
------------------------------------------------
| CustomerName | OrderID |
----------------------------------------------
| Ana Trujillo Emparedados y helados | 10308 |
| Antonio Moreno Taquería | 10365 |
------------------------------------------------
LEFT JOIN
- Devuelve todas las filas de la tabla de la izquierda, incluso si no coinciden con la tabla de la derecha
- Query
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
LEFT JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
ORDER BY Customers.CustomerName;
- Ejemplo
- Resultado esperado
------------------------------------------------
| CustomerName | OrderID |
----------------------------------------------
| Alfreds Futterkiste | null |
| Ana Trujillo Emparedados y helados | 10308 |
------------------------------------------------
RIGHT JOIN
- Devuelve todas las filas de la tabla de la derecha, incluso si no coinciden con la tabla de la izquierda
- Query
SELECT Orders.OrderID, Employees.FirstName
FROM Orders
RIGHT JOIN Employees
ON Orders.EmployeeID=Employees.EmployeeID
ORDER BY Orders.OrderID;
- Ejemplo
- Resultado esperado
------------------------
| OrderID | FirstName |
-----------------------
| | Adam |
| 10248 | Steve |
------------------------
FULL OUTER JOIN
- Devuelve todas las filas de la tabla de la derecha y de la izquierda incluso si no coinciden
- Query
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
FULL OUTER JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
ORDER BY Customers.CustomerName;
- Ejemplo
- Resultado esperado
------------------------------------------------
| CustomerName | OrderID |
----------------------------------------------
| Alfreds Futterkiste | |
| Ana Trujillo Emparedados y helados | 10308 |
| | 10382 |
------------------------------------------------
Con Joins
SELECT R.departamento, SUM(P.precio) FROM registradoras R
JOIN ventas V ON R.id = V.registradora_id
JOIN productos P ON P.id = V.producto_id
GROUP BY R.departamento;
Sin Joins
/* SIN JOIN */
SELECT R.departamento, SUM(P.precio)
FROM registradoras R, ventas V, productos P
WHERE R.id = V.registradora_id AND P.id = V.producto_id
GROUP BY R.departamento;
UNION - Acumula los resultados de dos sentencias SELECT
- Seleccionar personas cuyo apellido1 esté entre 'FERNANDEZ y 'HUERTAS'
SELECT City FROM Customers
UNION
SELECT City FROM Suppliers
ORDER BY City;
INTO
- Copiando toda una tabla en otra
SELECT *
INTO personasBackup
FROM personas;
- Copiando toda una tabla en otra base de datos
SELECT *
INTO nuevatabla [IN nuevabasedatos]
FROM tablaactual;
- Copiando resultados filtrados de una tabla en otra
SELECT *
INTO personasBackup
FROM personas
WHERE nombre = 'ANTONIO';
- Copiando el resutlado de un JOIN en otra tabla
SELECT personas.nombre, personas.apellido1, departamentos.departamento
INTO personasInformatica
FROM personas INNER JOIN departamentos
ON personas.dep = 'INFORMATICA';
- Limitan el tipo de dato que puede recibir una columna NOT NULL
- No acepta el valor NULL, siempre tiene que tener datos
CREATE TABLE personas
{
nombre varchar(255) NOT NULL,
apellido1 varchar(255) NOT NULL,
apellido2 varchar(255)
};
UNIQUE
- Evita que se use el mismo dato en entre las filas de una columna. Ideal para identificadores
CREATE TABLE personas
{
identificador int NOT NULL,
nombre varchar(255) NOT NULL,
apellido1 varchar(255) NOT NULL,
apellido2 varchar(255),
UNIQUE (identificador)
};
- Crear una id en una tabla ya creada previamente
ALTER TABLE Persons
ADD UNIQUE (P_Id);
- Eliminar la Restricción
ALTER TABLE Persons
DROP INDEX uc_PersonID
PRIMARY KEY
- Clave primaria en una columna
CREATE TABLE personas
{
identificador int NOT NULL,
nombre varchar(255) NOT NULL,
apellido1 varchar(255) NOT NULL,
PRIMARY KEY (identificador)
};
- Clave primaria usando multiples columnas
CREATE TABLE personas
{
identificador int NOT NULL,
nombre varchar(255) NOT NULL,
apellido1 varchar(255) NOT NULL,
CONSTRAINT pers PRIMARY KEY (identificador, nombre)
};
FOREIGN KEY
- Relaciona la clave primaria de otra tabla
CREATE TABLE departamentos
{
dep int NOT NULL PRIMARY KEY,
departamento varchar(255),
};
CREATE TABLE personas
{
per int NOT NULL PRIMARY KEY,
nombre varchar(255),
apellido1 varchar(255),
dep int FOREIGN KEY REFERENCES departamentos (dep)
};
CHECK
- Verifica que los valores cumplen ciertas condicciones antes de ser incluidos
CREATE TABLE Persons
(
P_Id int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255),
CHECK (P_Id>0)
);
DEFAULT
- Valor por defecto
CREATE TABLE Persons
(
P_Id int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255) DEFAULT 'Sandnes'
);
- Valor por defecto usando funciones
CREATE TABLE Orders
(
O_Id int NOT NULL,
OrderNo int NOT NULL,
P_Id int,
OrderDate date DEFAULT GETDATE()
);
Acelerando las búsquedas (pueden repetirse los valores de la columna)
CREATE INDEX nombreindice
ON nombretabla (nombrecolumna);
Acelerando las búsquedas (NO pueden repetirse los valores de la columna)
CREATE UNIQUE INDEX nombreindice
ON nombretabla (nombrecolumna);
Índices en múltiples columnas
CREATE INDEX indice2personas
ON personas(apellido1, apellido2);
Crear tabla con autoincremento
CREATE TABLE personas
{
persona int NOT NULL AUTO_INCREMENT,
nombre varchar(255),
apellido1 varchar(255),
apellido2 varchar(255)
};
Autoincremento partiendo de un número diferente a 0
ALTER TABLE personas AUTO_INCREMENT=100;
Crear una vista
CREATE VIEW [personas que se llaman ANTONIO] AS
SELECT nombre, apellido1, apellido2,edad
FROM personas
WHERE nombre = 'ANTONIO';
Consultar la vista
SELECT * FROM [personas que se llama ANTONIO]
Remplazar la vista
REPLACE VIEW [personas que se llama ANTONIO] AS
SELECT nombre, apellido1, apellido2, edad
FROM personas
WHERE edad > 20;
Eliminar la vista
DROP VIEW nombrevista;
Funciones
- NOW() Devuelve la fecha actual y la hora
- CURDATE() Devuelve la fecha actual
- CURTIME() devuelve la hora actual
- DATE() Extrae la fecha de un dato tipo fecha
- EXTRACT() Extrae una parte concreta (año, dia, hora, etc..) de un dato tipo fecha
- DATE_ADD() Añade un tiempo determinado a una fecha en el formato deseado
- DATE_SUB() Resta un tiempo determinado a una fecha en el formato deseado
- DATEDIFF() Devuelve el periodo entre dos fechas
- DATE_FORMAT() Devuelve formatos personalizados en las fechas
Ejemplo
CREATE TABLE pedidos
(
idpedido int NOT NULL,
nombreproducto varchar(50) NOT NULL,
fechapedido datetime NOT NULL
PRIMARY KEY (idpedido)
);
Filtrando por NULL
SELECT * FROM personas WHERE apellido2 IS NULL
Evitando NULL
SELECT * FROM personas WHERE apellido2 IS NOT NULL
Sustituyendo NULL
SELECT producto,
preciounidad * (unidadesstock + IFNULL(unidadespedido, 0)
FROM productos;
UCASE()
Convierte a mayúsculasLCASE()
Convierte a minúsculasMID()
Extrae los carácteresLEN()
Devuelve la logitud de un textoROUND()
Redondea al número de decimales especificadosNOW()
Retorna la hora y fecha actual del sistemaFORMAT()
Define como se ofrmatearán los campos
AVG()
Retorna el promedioCOUNT()
Retorna el número de filasFIRST()
Retorna el primer/os valor/esLAST()
Retorna el último/s valor/esMAX()
Retorna el valor mayorMIN()
Retorna el valor menosSUM()
Suma
Agrupa contenidos
SELECT Shippers.ShipperName,COUNT(Orders.OrderID) AS NumberOfOrders FROM Orders
LEFT JOIN Shippers
ON Orders.ShipperID=Shippers.ShipperID
GROUP BY ShipperName;
Clasico ejemplo
//Código vulnerable
const consulta = `SELECT * FROM usuarios WHERE nombre = '${nombreUsuario}';`;
// Comporptamiento esperado...
nombreUsuario = "Yo Mismo"
// Hack...
nombreUsuario = "'; DROP TABLE usuarios; SELECT * FROM datos WHERE nombre LIKE '%"
Recursos
- Wikipedia | Inyección SQL
- OWASP | Inyección SQL
- Github MySQL | Escaping query values
- Common Node.js Attack Vector: SQL Injection
- Secure Node Apps Against OWASP Top 10 - Injection
- How to Prevent SQL injection in Node Js
Documentación
- Web Oficial
- Why MySQL?
- Case Studies
- MySQL Performance Tuning and Optimization Resources
- Benchmarks
- White Papers
- Documentación
- MySQL 8.0 Reference Manual
- Github | Awesome MySQL
Uso en Nodejs
import mysql from 'mysql';
const connection = mysql.createConnection({
host : 'localhost',
user : 'me',
password : 'secret',
database : 'my_db'
});
connection.connect();
connection.query('SELECT 1 + 1 AS solution', (error, results, fields) => {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
connection.end();
Recursos
- w3School | Node.js MySQL
- Using MySQL with Node.js and the mysql JavaScript Client
- Build a simple app using Node JS and MySQL
- MySQL Node.js
- Node.js and MySQL tutorial
- Create a MySQL Database Middleware with Node.js 8 and Async/Await
- Top 3 MySQL drivers for NodeJS application
- Express DOC | Integración de la base de datos
- Make a NodeJS API with mySQL
- Node.js + MySQL Example: Handling 100's of GigaBytes of Data
Documentación
- Web Oficial
- Download
- Learn
- MariaDB - Getting Started With the Node.js Connector
- Github - MariaDB Node.js connector
- Useful MariaDB Queries
- A 10-minute MariaDB primer
- List of basic SQL statements
- Introduction to JOINS
- Guides and whitepapers
- @mariadb en Twitter
Uso en Nodejs
const mariadb = require('mariadb');
const pool = mariadb.createPool({host: 'mydb.com', user:'myUser', connectionLimit: 5});
async function asyncFunction() {
let conn;
try {
conn = await pool.getConnection();
const rows = await conn.query("SELECT 1 as val");
console.log(rows); //[ {val: 1}, meta: ... ]
const res = await conn.query("INSERT INTO myTable value (?, ?)", [1, "mariadb"]);
console.log(res); // { affectedRows: 1, insertId: 1, warningStatus: 0 }
} catch (err) {
throw err;
} finally {
if (conn) return conn.end();
}
}
Recursos
Documentación
Uso en Nodejs
const { Client } = require('pg')
const client = new Client()
await client.connect()
const res = await client.query('SELECT $1::text as message', ['Hello world!'])
console.log(res.rows[0].message) // Hello world!
await client.end()
Recursos
- PostgreSQL and NodeJS
- Connect to PostgreSQL database server using psql
- ¿Cómo usar bases de datos Postgres con Node.js?
- Cómo crear un API JSON en PostgreSQL con NodeJS
- Getting Started with Node, Express and Postgres Using Sequelize
- PostgreSQL NodeJS Tutorial
- Back-end Basics with Node.js, PostgreSQL, Sequelize, and FeathersJS
- Stackoverflow | How to make connection to Postgres via Node.js
- How to build a Node.js API using Postgres, Lambda and API Gateway
- Node.js GraphQL & PostgreSQL Quickstart
- Deploying a Node.js + PostgreSQL app to Heroku
- Node Hero - Node.js Database Tutorial
- Setting up a RESTful API with Node.js and PostgreSQL
- Fetch the data from multiple tables using postgresql and sequelize