miércoles, 29 de julio de 2026

Capítulo 1. Introducción

Bienvenida al curso

Bienvenido al curso Desarrollo de Aplicaciones Web con Angular 19 y ASP.NET Core 9. A lo largo de este curso aprenderás a combinar estas dos tecnologías para construir aplicaciones web modernas, escalables y listas para entornos de producción.

Angular es uno de los frameworks más utilizados para el desarrollo de interfaces de usuario dinámicas, mientras que ASP.NET Core proporciona una plataforma robusta y de alto rendimiento para la creación de servicios web y APIs. La integración de ambas tecnologías permite desarrollar soluciones completas bajo una arquitectura moderna cliente-servidor.

Objetivos del curso

Durante el desarrollo del curso se abordarán los fundamentos de Angular y ASP.NET Core mediante un enfoque práctico, construyendo una aplicación desde cero.

Al finalizar el curso, serás capaz de:

  • Comprender los conceptos fundamentales de Angular y ASP.NET Core.

  • Desarrollar aplicaciones web utilizando una arquitectura basada en frontend y backend desacoplados.

  • Consumir APIs REST desde aplicaciones Angular.

  • Implementar operaciones de creación, consulta, actualización y eliminación de datos (CRUD).

  • Aplicar buenas prácticas de desarrollo y organización de proyectos.

  • Publicar una aplicación completa en un entorno de producción.

Metodología

El aprendizaje se realizará de forma progresiva mediante la construcción de un proyecto real. Cada módulo incorporará nuevos conceptos y funcionalidades que permitirán comprender cómo interactúan Angular y ASP.NET Core dentro de una aplicación moderna.

Además de los aspectos teóricos, se desarrollarán ejercicios prácticos que permitirán consolidar los conocimientos adquiridos en cada etapa.

Acerca del instructor

El curso es impartido por Felipe Gavilán, desarrollador y consultor de software especializado en tecnologías Microsoft y desarrollo web moderno.

Próximos pasos

En los siguientes módulos se realizará una introducción más detallada a Angular y ASP.NET Core, revisando sus principales características, ventajas y el papel que desempeña cada tecnología dentro de la arquitectura de la aplicación que construiremos durante el curso.


viernes, 17 de julio de 2026

🐘 La Restricción UNIQUE en PostgreSQL

Hasta ahora hemos visto las restricciones:

  • NULL

  • NOT NULL

  • DEFAULT

Estas nos permiten controlar si una columna puede estar vacía o si debe recibir un valor predeterminado.

Sin embargo, existe otro problema común:

¿Cómo evitar que un mismo valor se almacene varias veces?

Por ejemplo:

  • Dos usuarios con el mismo correo electrónico.

  • Dos empleados con el mismo número de empleado.

  • Dos productos con el mismo código.

Para resolver este problema PostgreSQL proporciona la restricción UNIQUE.


🧠 ¿Qué es UNIQUE?

La restricción UNIQUE garantiza que los valores almacenados en una columna no se repitan.

En otras palabras:

✅ Valores diferentes son permitidos.

❌ Valores duplicados generan error.


🏗️ Sintaxis Básica

La forma más simple de definirla es durante la creación de una tabla.

CREATE TABLE usuarios (

id INTEGER,

nombre VARCHAR(100),

email VARCHAR(200) UNIQUE

);

En este ejemplo:

  • Dos usuarios pueden tener distintos correos.

  • No pueden existir dos usuarios con el mismo correo.


✅ Insertar Valores Únicos

Creamos la tabla:

CREATE TABLE usuarios (

id INTEGER,

nombre VARCHAR(100),

email VARCHAR(200) UNIQUE

);

Insertamos el primer usuario:

INSERT INTO usuarios (

id,

nombre,

email

)

VALUES (

1,

'Juan Pérez',

'juan@email.com'

);

Insertamos un segundo usuario:

INSERT INTO usuarios (

id,

nombre,

email

)

VALUES (

2,

'Ana López',

'ana@email.com'

);

Ambos registros se insertan correctamente porque los correos son diferentes.


❌ Intentar Insertar un Duplicado

Ahora intentemos insertar un correo que ya existe.

INSERT INTO usuarios (

id,

nombre,

email

)

VALUES (

3,

'Carlos García',

'juan@email.com'

);

PostgreSQL devolverá un error similar a:

ERROR: duplicate key value violates unique constraint

La inserción falla porque el valor:

juan@email.com

ya se encuentra almacenado.


🔍 Verificando los Datos

Podemos consultar la tabla:

SELECT *

FROM usuarios;

Resultado:

id | nombre | email

----+-------------+----------------

1 | Juan Pérez | juan@email.com

2 | Ana López | ana@email.com

Observa que el tercer registro nunca fue insertado.


📝 UNIQUE en Otras Columnas

La restricción no está limitada a correos electrónicos.

También suele utilizarse en:

  • RFC

  • CURP

  • Número de empleado

  • Código de producto

  • Nombre de usuario

  • Número de serie

Ejemplo:

CREATE TABLE productos (

codigo VARCHAR(50) UNIQUE,

nombre VARCHAR(100),

precio NUMERIC(10,2)

);


🧪 Ejemplo Completo

Crear Tabla

CREATE TABLE empleados (

numero_empleado INTEGER UNIQUE,

nombre VARCHAR(100),

departamento VARCHAR(100)

);


Insertar Datos

INSERT INTO empleados (

numero_empleado,

nombre,

departamento

)

VALUES

(

1001,

'Juan Pérez',

'Tecnología'

),

(

1002,

'Ana López',

'Finanzas'

);


Consultar

SELECT *

FROM empleados;

Resultado:

numero_empleado | nombre | departamento

----------------+-------------+--------------

1001 | Juan Pérez | Tecnología

1002 | Ana López | Finanzas


Intentar duplicar el número de empleado

INSERT INTO empleados (

numero_empleado,

nombre,

departamento

)

VALUES (

1001,

'Carlos García',

'Ventas'

);

Resultado:

ERROR: duplicate key value violates unique constraint


⚠️ UNIQUE y Valores NULL

Este es uno de los comportamientos que más confunde a quienes comienzan con PostgreSQL.

Supongamos la siguiente tabla:

CREATE TABLE clientes (

id INTEGER,

email VARCHAR(200) UNIQUE

);

Ahora insertamos:

INSERT INTO clientes (id, email)

VALUES (1, NULL);

y posteriormente:

INSERT INTO clientes (id, email)

VALUES (2, NULL);

Ambas inserciones son válidas.


¿Por qué ocurre esto?

Porque PostgreSQL considera que:

NULL != NULL

Un valor nulo significa "valor desconocido", por lo que múltiples registros pueden contener NULL en una columna UNIQUE.

Por esta razón es común combinar:

UNIQUE

con

NOT NULL


🔒 UNIQUE + NOT NULL

Esta es probablemente la combinación más utilizada.

CREATE TABLE usuarios (

id INTEGER,

email VARCHAR(200) NOT NULL UNIQUE

);

Con esta definición:

✅ El correo es obligatorio.

✅ No puede repetirse.

❌ No puede ser NULL.


🏗️ UNIQUE a Nivel de Tabla

Hasta ahora hemos definido UNIQUE directamente sobre una columna.

También puede definirse al final de la tabla.

CREATE TABLE usuarios (

id INTEGER,

nombre VARCHAR(100),

email VARCHAR(200),

UNIQUE(email)

);

El comportamiento es exactamente el mismo.


🔧 Agregar UNIQUE a una Tabla Existente

Si la tabla ya existe:

ALTER TABLE usuarios

ADD CONSTRAINT uq_usuarios_email

UNIQUE(email);

A partir de ese momento PostgreSQL impedirá valores duplicados.


🔧 Eliminar una Restricción UNIQUE

Primero identificamos el nombre de la restricción.

Posteriormente:

ALTER TABLE usuarios

DROP CONSTRAINT uq_usuarios_email;


🎯 UNIQUE en Múltiples Columnas

También podemos exigir que una combinación de columnas sea única.

Supongamos una tabla de cursos.

CREATE TABLE inscripciones (

alumno VARCHAR(100),

curso VARCHAR(100),

CONSTRAINT uq_inscripciones_alumno_curso

UNIQUE(alumno, curso)

);

Esto significa:

✅ Juan puede inscribirse a SQL.

✅ Juan puede inscribirse a PostgreSQL.

✅ Ana puede inscribirse a SQL.

❌ Juan no puede inscribirse dos veces al mismo curso.


Ejemplo

INSERT INTO inscripciones

VALUES ('Juan', 'PostgreSQL');

Luego:

INSERT INTO inscripciones

VALUES ('Juan', 'PostgreSQL');

Resultado:

ERROR: duplicate key value violates unique constraint


💡 Buenas Prácticas

Utiliza UNIQUE en datos que realmente deban ser únicos

Ejemplos comunes:

email

usuario

rfc

curp

codigo_producto

numero_empleado


Combínalo con NOT NULL cuando corresponda

En muchos casos ambos requisitos son necesarios.

email VARCHAR(200) NOT NULL UNIQUE


Asigna nombres descriptivos a las restricciones

Por ejemplo:

ALTER TABLE usuarios

ADD CONSTRAINT uq_usuarios_email

UNIQUE(email);

Esto facilita la identificación de errores y el mantenimiento de la base de datos.


No agregues UNIQUE innecesariamente

Pregúntate siempre:

¿Este dato realmente debe ser único?

Por ejemplo, normalmente no tendría sentido que el nombre de una persona fuera único:

nombre VARCHAR(100) UNIQUE

Podrían existir múltiples personas llamadas "Juan Pérez".


✅ Conclusión

La restricción UNIQUE permite garantizar que ciertos valores no se repitan dentro de una tabla.

Los conceptos más importantes son:

  • UNIQUE evita valores duplicados.

  • Puede definirse sobre una o varias columnas.

  • Los intentos de insertar valores repetidos generan error.

  • Varias filas pueden contener NULL en una columna UNIQUE.

  • Es habitual combinar UNIQUE con NOT NULL.

  • Se utiliza frecuentemente para correos electrónicos, nombres de usuario, códigos de producto y números de empleado.

🐘 La Restricción DEFAULT en PostgreSQL

 En el capítulo anterior vimos cómo utilizar NULL y NOT NULL para controlar si una columna puede o no quedar sin información.

Sin embargo, existe una situación muy común:

¿Qué ocurre cuando no quiero que el usuario capture un valor, pero tampoco quiero almacenar NULL?

Para estos casos PostgreSQL proporciona la restricción DEFAULT.


🧠 ¿Qué es DEFAULT?

DEFAULT permite asignar un valor predeterminado a una columna cuando el usuario no proporciona uno durante un INSERT.

En otras palabras:

Si no se especifica un valor, PostgreSQL utilizará automáticamente el valor definido en DEFAULT.


🏗️ Sintaxis

La cláusula DEFAULT se define durante la creación de la tabla.

CREATE TABLE tabla (
columna tipo_dato DEFAULT valor
);

Ejemplo:

CREATE TABLE empleados (
id INTEGER,
nombre VARCHAR(100),
activo BOOLEAN DEFAULT TRUE
);

En este caso:

  • Si se proporciona un valor para activo, PostgreSQL lo utilizará.
  • Si no se proporciona, PostgreSQL asignará TRUE.

✅ Primer Ejemplo

Crear la tabla

CREATE TABLE empleados (
id INTEGER,
nombre VARCHAR(100),
activo BOOLEAN DEFAULT TRUE
);


Insertar un registro sin especificar el campo activo

INSERT INTO empleados (
id,
nombre
)
VALUES (
1,
'Juan Pérez'
);

Observa que no enviamos ningún valor para activo.


Consultar los datos

SELECT *
FROM empleados;

Resultado:

id | nombre | activo
----+--------------+--------
1 | Juan Pérez | true

PostgreSQL asignó automáticamente el valor definido en DEFAULT.


✏️ Insertar un valor diferente al DEFAULT

El valor predeterminado no es obligatorio.

Si especificamos un valor durante el INSERT, PostgreSQL utilizará ese valor.

INSERT INTO empleados (
id,
nombre,
activo
)
VALUES (
2,
'Ana López',
FALSE
);

Consultar:

SELECT *
FROM empleados;

Resultado:

id | nombre | activo
----+--------------+--------
1 | Juan Pérez | true
2 | Ana López | false


📅 DEFAULT con fechas

Uno de los usos más frecuentes es almacenar automáticamente fechas de creación.

Crear tabla

CREATE TABLE productos (
codigo INTEGER,
nombre VARCHAR(100),
fecha_creacion DATE DEFAULT CURRENT_DATE
);


Insertar registro

INSERT INTO productos (
codigo,
nombre
)
VALUES (
1001,
'Laptop'
);


Consultar

SELECT *
FROM productos;

Resultado:

codigo | nombre | fecha_creacion
--------+--------+---------------
1001 | Laptop | 2026-07-17

PostgreSQL asignó automáticamente la fecha actual.


🕒 DEFAULT con Timestamp

También es muy común registrar automáticamente la fecha y hora de creación.

CREATE TABLE logs (
id INTEGER,
mensaje TEXT,
fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Insertar:

INSERT INTO logs (
id,
mensaje
)
VALUES (
1,
'Aplicación iniciada'
);

Consultar:

SELECT *
FROM logs;

Resultado:

id | mensaje | fecha_registro
----+----------------------+-------------------------
1 | Aplicación iniciada | 2026-07-17 15:32:10


🔢 DEFAULT para números

También podemos definir valores numéricos predeterminados.

CREATE TABLE productos (
codigo INTEGER,
nombre VARCHAR(100),
stock INTEGER DEFAULT 0
);

Insertar:

INSERT INTO productos (
codigo,
nombre
)
VALUES (
1001,
'Mouse'
);

Resultado:

codigo | nombre | stock
--------+--------+-------
1001 | Mouse | 0


📝 DEFAULT para texto

CREATE TABLE tickets (
id INTEGER,
descripcion TEXT,
estado VARCHAR(20) DEFAULT 'ABIERTO'
);

Insertar:

INSERT INTO tickets (
id,
descripcion
)
VALUES (
1,
'Error de acceso al sistema'
);

Consultar:

SELECT *
FROM tickets;

Resultado:

id | descripcion | estado
----+-----------------------------+---------
1 | Error de acceso al sistema | ABIERTO


⚠️ Diferencia entre NULL y DEFAULT

Es importante entender esta diferencia.

Supongamos la siguiente tabla:

CREATE TABLE usuarios (
id INTEGER,
activo BOOLEAN DEFAULT TRUE
);


Caso 1: No enviar el valor

INSERT INTO usuarios (id)
VALUES (1);

Resultado:

activo = TRUE

Se utiliza el valor definido en DEFAULT.


Caso 2: Insertar NULL explícitamente

INSERT INTO usuarios (
id,
activo
)
VALUES (
2,
NULL
);

Resultado:

activo = NULL

En este caso PostgreSQL no utiliza el valor por defecto porque el usuario proporcionó explícitamente un valor: NULL.


🔒 Combinando NOT NULL y DEFAULT

Es muy común utilizar ambas restricciones juntas.

CREATE TABLE usuarios (
id INTEGER,
nombre VARCHAR(100) NOT NULL,
activo BOOLEAN NOT NULL DEFAULT TRUE
);

Beneficios:

  • No se permiten valores nulos.
  • Si el usuario no envía un valor, PostgreSQL utiliza el valor predeterminado.

Ejemplo:

INSERT INTO usuarios (
id,
nombre
)
VALUES (
1,
'Juan Pérez'
);

Resultado:

activo = TRUE


🔧 Agregar DEFAULT a una columna existente

Supongamos que la tabla ya existe.

ALTER TABLE empleados
ALTER COLUMN activo SET DEFAULT TRUE;

A partir de ese momento, los nuevos registros utilizarán ese valor predeterminado.


🔧 Eliminar DEFAULT

Si ya no deseas un valor por defecto:

ALTER TABLE empleados
ALTER COLUMN activo DROP DEFAULT;


🧪 Ejemplo Completo

Crear tabla

CREATE TABLE clientes (
id INTEGER,
nombre VARCHAR(100) NOT NULL,
activo BOOLEAN DEFAULT TRUE,
fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
pais VARCHAR(50) DEFAULT 'México'
);


Insertar registros

INSERT INTO clientes (
id,
nombre
)
VALUES
(
1,
'Juan Pérez'
),
(
2,
'Ana López'
);


Consultar

SELECT *
FROM clientes;

Resultado aproximado:

id | nombre | activo | fecha_registro | pais
----+-------------+--------+----------------------+--------
1 | Juan Pérez | true | 2026-07-17 15:00:00 | México
2 | Ana López | true | 2026-07-17 15:00:05 | México

Observa cómo PostgreSQL asignó automáticamente los valores de las columnas que no fueron proporcionadas.


💡 Buenas prácticas

Utiliza DEFAULT para valores frecuentes

Por ejemplo:

activo BOOLEAN DEFAULT TRUE


Automatiza fechas de creación

fecha_creacion TIMESTAMP DEFAULT CURRENT_TIMESTAMP


Combina DEFAULT con NOT NULL

Esto evita valores nulos y simplifica los INSERT.

estado VARCHAR(20) NOT NULL DEFAULT 'ACTIVO'


Evita valores por defecto que puedan generar confusión

Por ejemplo:

salario NUMERIC(10,2) DEFAULT 0

En algunos sistemas podría ser difícil distinguir entre:

  • Salario realmente igual a 0
  • Salario aún no capturado

Analiza cada caso de negocio antes de definir el valor predeterminado.


✅ Conclusión

La restricción DEFAULT permite que PostgreSQL asigne automáticamente valores cuando una columna no es incluida en un INSERT.

Los conceptos más importantes son:

  • DEFAULT define un valor predeterminado.
  • Solo se utiliza cuando la columna no recibe un valor durante el INSERT.
  • Puede utilizarse con números, texto, fechas, timestamps y valores booleanos.
  • Es común combinarlo con NOT NULL.
  • Ayuda a simplificar las inserciones y mantener la consistencia de los datos.

🐘 NULL y NOT NULL en PostgreSQL

Hasta ahora hemos aprendido a crear tablas y manipular datos mediante INSERT, SELECT, UPDATE y DELETE. Sin embargo, todavía no hemos hablado de una pregunta fundamental:

¿Qué ocurre cuando no conocemos el valor de un dato?

Para responder esta pregunta, PostgreSQL utiliza el concepto de NULL.


🧠 ¿Qué es NULL?

NULL representa la ausencia de un valor.

No significa:

  • Cero (0)
  • Cadena vacía ('')
  • Espacio en blanco (' ')

Significa simplemente:

"No existe un valor almacenado para esta columna."

Por ejemplo, supongamos una tabla de empleados:

idnombretelefono
1Juan Pérez555123456
2Ana LópezNULL

En este caso, no sabemos el teléfono de Ana López o simplemente no se ha registrado.


📦 ¿Cuándo utilizar NULL?

Algunos ejemplos comunes son:

  • Un cliente aún no ha proporcionado su teléfono.
  • Un empleado no tiene fecha de baja.
  • Un producto todavía no tiene descripción.
  • Un pedido aún no ha sido entregado.

En estos casos, permitir valores NULL tiene sentido.


🔒 ¿Qué es NOT NULL?

NOT NULL es una restricción que obliga a proporcionar un valor para una columna.

Cuando una columna tiene la restricción NOT NULL:

✅ Se debe proporcionar un valor.

❌ No se permite almacenar NULL.


🏗️ Crear una tabla con NOT NULL

Supongamos que estamos creando una tabla de empleados.

CREATE TABLE empleados (
id INTEGER NOT NULL,
nombre VARCHAR(100) NOT NULL,
departamento VARCHAR(100),
salario NUMERIC(10,2)
);

En este ejemplo:

  • id es obligatorio.
  • nombre es obligatorio.
  • departamento es opcional.
  • salario es opcional.

✅ Insertar datos válidos

Este INSERT funciona correctamente:

INSERT INTO empleados (
id,
nombre,
departamento,
salario
)
VALUES (
1,
'Juan Pérez',
'Tecnología',
25000.00
);

Todos los campos obligatorios contienen un valor.


❌ Intentar insertar NULL en una columna NOT NULL

Ahora intentemos insertar un empleado sin nombre.

INSERT INTO empleados (
id,
nombre,
departamento,
salario
)
VALUES (
2,
NULL,
'Finanzas',
30000.00
);

PostgreSQL devolverá un error similar a:

ERROR: null value in column "nombre"
violates not-null constraint

Esto ocurre porque la columna nombre fue definida como NOT NULL.


❌ Omitir una columna obligatoria

También obtendremos un error si omitimos una columna obligatoria.

INSERT INTO empleados (
id,
departamento
)
VALUES (
3,
'Recursos Humanos'
);

Resultado:

ERROR: null value in column "nombre"
violates not-null constraint

Aunque no escribimos explícitamente NULL, PostgreSQL intentó asignarlo automáticamente al no encontrar un valor para la columna.


✅ Insertar NULL en columnas que lo permiten

Las columnas sin NOT NULL aceptan valores nulos.

INSERT INTO empleados (
id,
nombre,
departamento,
salario
)
VALUES (
4,
'Ana López',
NULL,
NULL
);

Este registro se insertará correctamente.


🔍 Consultar valores NULL

Veamos los datos:

SELECT *
FROM empleados;

Resultado:

id | nombre | departamento | salario
----+-------------+--------------+----------
1 | Juan Pérez | Tecnología | 25000.00
4 | Ana López | NULL | NULL


⚠️ Comparar NULL correctamente

Uno de los errores más comunes es intentar buscar valores NULL utilizando el operador =.

❌ Incorrecto

SELECT *
FROM empleados
WHERE departamento = NULL;

Esta consulta no devolverá resultados.


Forma correcta

Para buscar valores nulos se utilizan:

IS NULL

o

IS NOT NULL


Buscar registros con NULL

SELECT *
FROM empleados
WHERE departamento IS NULL;


Buscar registros con valor

SELECT *
FROM empleados
WHERE departamento IS NOT NULL;


🧪 Ejemplo completo

Crear tabla

CREATE TABLE productos (
codigo INTEGER NOT NULL,
nombre VARCHAR(100) NOT NULL,
descripcion TEXT,
precio NUMERIC(10,2),
fecha_alta DATE
);


Insertar registro válido

INSERT INTO productos (
codigo,
nombre,
descripcion,
precio,
fecha_alta
)
VALUES (
1001,
'Laptop',
'Equipo portátil',
18000.00,
'2026-07-01'
);


Insertar registro con campos opcionales

INSERT INTO productos (
codigo,
nombre
)
VALUES (
1002,
'Monitor'
);

Funciona porque únicamente se omitieron columnas que permiten NULL.


Intentar omitir un campo obligatorio

INSERT INTO productos (
codigo
)
VALUES (
1003
);

Resultado:

ERROR: null value in column "nombre"
violates not-null constraint


🔧 Agregar NOT NULL a una columna existente

También es posible modificar una tabla ya creada.

Por ejemplo:

ALTER TABLE empleados
ALTER COLUMN nombre SET NOT NULL;

A partir de ese momento todos los registros nuevos deberán incluir un valor para nombre.


🔧 Eliminar NOT NULL

Si posteriormente decidimos permitir valores nulos:

ALTER TABLE empleados
ALTER COLUMN nombre DROP NOT NULL;


💡 Buenas prácticas

Usa NOT NULL en datos obligatorios

Generalmente deberían ser obligatorios:

  • Nombre de un cliente
  • Nombre de un producto
  • Correo electrónico (dependiendo del sistema)
  • Fecha de creación
  • Identificadores

Ejemplo:

nombre VARCHAR(100) NOT NULL


No uses NOT NULL en información opcional

Por ejemplo:

  • Segundo apellido
  • Comentarios
  • Observaciones
  • Fecha de baja

Estos campos suelen permitir valores nulos.


Define la obligatoriedad desde el diseño

Es más fácil decidir desde el principio qué datos son obligatorios que modificar tablas con millones de registros posteriormente.


✅ Conclusión

NULL representa la ausencia de un valor, mientras que NOT NULL obliga a que una columna siempre tenga información.

Los conceptos más importantes son:

  • NULL no es cero ni una cadena vacía.
  • Las columnas permiten NULL por defecto.
  • NOT NULL convierte una columna en obligatoria.
  • Intentar insertar NULL en una columna NOT NULL genera un error.
  • Para buscar valores nulos se utiliza IS NULL.
  • Para buscar valores no nulos se utiliza IS NOT NULL.


Capítulo 1. Introducción