FullStackJS Camp
Módulo 5·teoria·4h
Objetivos de aprendizaje
  • Distinguir DDL de DML y comprender cuándo usar cada uno.
  • Crear bases de datos y tablas con la sintaxis correcta.
  • Elegir el tipo de dato apropiado para cada columna.
  • Aplicar constraints: PRIMARY KEY, FOREIGN KEY, NOT NULL, UNIQUE, DEFAULT.
  • Usar AUTO_INCREMENT para identificadores automáticos.

Definición de Tablas DDL (Parte I)

DDL (Data Definition Language) es el subconjunto de SQL que define y modifica la estructura de la base de datos: bases de datos, tablas, índices y restricciones.

CategoríaSentencias
DDLCREATE, ALTER, DROP, TRUNCATE, RENAME
DMLSELECT, INSERT, UPDATE, DELETE

La diferencia clave: DDL cambia el esquema (la estructura), DML cambia los datos.


CREATE DATABASE

sql
-- Crear la base de datos con codificación UTF-8
CREATE DATABASE alke_wallet
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

-- Seleccionar la base de datos activa
USE alke_wallet;

-- Ver todas las bases de datos disponibles
SHOW DATABASES;

Tipos de datos

Elegir el tipo correcto es fundamental: afecta el almacenamiento, la validación y el rendimiento.

Numéricos

TipoRangoUso
TINYINT-128 a 127Edad, flags pequeños
SMALLINT-32768 a 32767Cantidades pequeñas
INT / INTEGER-2.1B a 2.1BIDs, contadores
BIGINT-9.2Q a 9.2QIDs de sistemas grandes
DECIMAL(p,s)ExactoDinero, precios
FLOAT / DOUBLEAproximadoCálculos científicos
sql
-- DECIMAL(12, 2) = hasta 12 dígitos total, 2 decimales
-- Máximo: 9,999,999,999.99
saldo DECIMAL(12, 2) NOT NULL DEFAULT 0

-- INT con UNSIGNED duplica el rango positivo (0 a 4.2B)
cantidad INT UNSIGNED NOT NULL DEFAULT 0

Texto

TipoAlmacenamientoUso
CHAR(n)Fijo — siempre n bytesCódigos de longitud fija (ISO, RUT)
VARCHAR(n)Variable — hasta n bytesNombres, emails, URLs
TEXTHasta 65,535 bytesDescripciones largas
MEDIUMTEXTHasta 16 MBArtículos, logs
LONGTEXTHasta 4 GBDocumentos
sql
nombre     VARCHAR(80)  NOT NULL,
correo     VARCHAR(120) NOT NULL UNIQUE,
bio        TEXT,
codigo_iso CHAR(3)      NOT NULL   -- ej: 'CLP', 'USD', 'EUR'

Fechas y horas

TipoFormatoUso
DATEYYYY-MM-DDFecha sin hora (cumpleaños, vencimiento)
TIMEHH:MM:SSSolo hora
DATETIMEYYYY-MM-DD HH:MM:SSTimestamp sin zona horaria
TIMESTAMPYYYY-MM-DD HH:MM:SSTimestamp, se actualiza automáticamente
YEARYYYYSolo año
sql
created_at    DATE      NOT NULL DEFAULT (CURRENT_DATE),
updated_at    DATETIME  NOT NULL DEFAULT CURRENT_TIMESTAMP
                        ON UPDATE CURRENT_TIMESTAMP,
deleted_at    DATETIME  NULL

Booleanos y enumerados

sql
-- MySQL no tiene tipo BOOLEAN nativo — usa TINYINT(1)
activo    TINYINT(1) NOT NULL DEFAULT 1,  -- 1=true, 0=false

-- ENUM: lista fija de valores posibles
estado    ENUM('pendiente', 'aprobado', 'rechazado') NOT NULL DEFAULT 'pendiente',
tipo      ENUM('ingreso', 'egreso') NOT NULL

Constraints (Restricciones)

Los constraints son reglas que la base de datos aplica automáticamente para garantizar la integridad de los datos.

NOT NULL

sql
-- La columna no puede tener valor NULL (obligatoria)
nombre VARCHAR(80) NOT NULL

DEFAULT

sql
-- Valor asignado automáticamente si no se provee
saldo      DECIMAL(12,2) NOT NULL DEFAULT 0,
created_at DATE          NOT NULL DEFAULT (CURRENT_DATE),
activo     TINYINT(1)    NOT NULL DEFAULT 1

UNIQUE

sql
-- No puede haber dos filas con el mismo valor en esta columna
correo VARCHAR(120) NOT NULL UNIQUE,

-- UNIQUE compuesto (combinación única)
UNIQUE KEY uq_usuario_moneda (user_id, currency_id)

PRIMARY KEY

sql
-- Identifica de forma única cada fila — implica NOT NULL + UNIQUE
-- Forma 1: inline
user_id INT AUTO_INCREMENT PRIMARY KEY,

-- Forma 2: al final (necesario para PK compuesta)
PRIMARY KEY (user_id),

-- PK compuesta (ej: tabla intermedia N:N)
PRIMARY KEY (user_id, project_id)

AUTO_INCREMENT

sql
-- MySQL asigna el siguiente entero disponible automáticamente
user_id INT AUTO_INCREMENT PRIMARY KEY
-- INSERT sin especificar user_id → MySQL usa 1, 2, 3...

CREATE TABLE — Sintaxis completa

sql
CREATE TABLE usuarios (
  -- Columnas con tipos y constraints inline
  user_id    INT            AUTO_INCREMENT,
  nombre     VARCHAR(80)    NOT NULL,
  correo     VARCHAR(120)   NOT NULL,
  contrasena VARCHAR(120)   NOT NULL,
  saldo      DECIMAL(12,2)  NOT NULL DEFAULT 0,
  created_at DATE           NOT NULL DEFAULT (CURRENT_DATE),

  -- Constraints de tabla (al final)
  PRIMARY KEY (user_id),
  UNIQUE KEY  uq_correo (correo)
);
sql
CREATE TABLE monedas (
  currency_id     INT         AUTO_INCREMENT,
  currency_name   VARCHAR(60) NOT NULL,
  currency_symbol VARCHAR(10) NOT NULL,

  PRIMARY KEY (currency_id)
);

FOREIGN KEY

sql
CREATE TABLE transacciones (
  transaction_id   INT            AUTO_INCREMENT,
  sender_user_id   INT            NOT NULL,
  receiver_user_id INT            NOT NULL,
  valor            DECIMAL(12,2)  NOT NULL,
  transaction_date DATETIME       NOT NULL DEFAULT CURRENT_TIMESTAMP,

  PRIMARY KEY (transaction_id),

  -- Nombres de FK recomendados: fk_<tabla>_<columna>
  CONSTRAINT fk_trans_sender
    FOREIGN KEY (sender_user_id)   REFERENCES usuarios(user_id),
  CONSTRAINT fk_trans_receiver
    FOREIGN KEY (receiver_user_id) REFERENCES usuarios(user_id)
);

Orden de creación de tablas

Debes crear las tablas referenciadas primero (las que tienen la PK), y las tablas con FK después:

sql
-- ✅ Correcto: primero usuarios, luego transacciones
CREATE TABLE usuarios (...);
CREATE TABLE transacciones (
  ...,
  FOREIGN KEY (sender_user_id) REFERENCES usuarios(user_id)
);

-- ❌ Error: si intentas crear transacciones antes que usuarios,
-- MySQL no puede crear la FK porque la tabla referenciada no existe

SHOW — Explorar el esquema

sql
-- Ver tablas de la base de datos activa
SHOW TABLES;

-- Ver la definición completa de una tabla
SHOW CREATE TABLE usuarios;

-- Ver columnas con sus tipos y constraints
DESCRIBE usuarios;
-- o: SHOW COLUMNS FROM usuarios;

Script completo: Alke Wallet

sql
DROP DATABASE IF EXISTS alke_wallet;
CREATE DATABASE alke_wallet CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE alke_wallet;

CREATE TABLE usuarios (
  user_id    INT           AUTO_INCREMENT,
  nombre     VARCHAR(80)   NOT NULL,
  correo     VARCHAR(120)  NOT NULL,
  contrasena VARCHAR(120)  NOT NULL,
  saldo      DECIMAL(12,2) NOT NULL DEFAULT 0,
  created_at DATE          NOT NULL DEFAULT (CURRENT_DATE),
  PRIMARY KEY (user_id),
  UNIQUE KEY uq_correo (correo)
);

CREATE TABLE monedas (
  currency_id     INT         AUTO_INCREMENT,
  currency_name   VARCHAR(60) NOT NULL,
  currency_symbol VARCHAR(10) NOT NULL,
  PRIMARY KEY (currency_id)
);

CREATE TABLE transacciones (
  transaction_id   INT           AUTO_INCREMENT,
  sender_user_id   INT           NOT NULL,
  receiver_user_id INT           NOT NULL,
  valor            DECIMAL(12,2) NOT NULL,
  transaction_date DATETIME      NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (transaction_id),
  CONSTRAINT fk_trans_sender
    FOREIGN KEY (sender_user_id)   REFERENCES usuarios(user_id),
  CONSTRAINT fk_trans_receiver
    FOREIGN KEY (receiver_user_id) REFERENCES usuarios(user_id)
);