Curso PostgreSQL¶

    Autor: Luis Fernando Apáez Álvarez
    -Curso PyM-
    Clase 4:
    Fecha: Abril del 2023




Restricciones¶

Desde hace dos clase hemos estado trabajando con las restricciones sobre nuestras tablas. Dichas restricciones fueron especificamente las llaves primarias y foráneas, las cuales son de enorme importancia para maneter la integridad de los datos en nuestra BD; asimismo, las restricciones que veremos en esta clase son útiles para maneter dicha integridad.

Restricción CHECK¶

Comencemos por ver los primeros registros de la tabla empleados:

Captura1.PNG

y supongamos, por ejemplo, que por políticas de la empresa ningún empleado puede ganar más de 65000 mensuales. Así como hemos construido nuestra tabla no tendríamos problema alguno en ingresar un empleado cuyo salario exceda esta cifra. Por ello es necesario la implementación de una restricción sobre esta columna para impedir que se ingresen valores superiores a los 65000, lo cual conseguiremos al definir la restricción del tipo CHECK sobre al columna salario, de modo que con esta retricción logramos controlar los valores que se ingresan en una columna en especifico.

Para agregar dicha restricción escribimos:


ALTER TABLE <<nombre_tabla>> ADD CONSTRAINT ck_<<nombre_tabla>>_<<nombre_columna>> CHECK (<<condicion>>)

donde notamos que en el CHECK debemos definir alguna condición en especifico. En nuestro ejemplo, la condición sería que salario < 65000. Por consiguiente, definimos el siguiente CHECK sobre la columna salario:


ALTER TABLE empleados ADD CONSTRAINT ck_empleados_salario CHECK(salario < 65000);

cuando lo ejecutemos probablemente nos salga un error que nos diga que dicha restricción es violada por algunos registros en nuestra tabla, es decir, ya existen empleados que ganan más de 65000. En mi caso sólo hay un empleado y éste es:


SELECT * FROM empleados WHERE salario > 65000;

Captura2.PNG

cuyo salario es exorbitante. Recordemos que los datos los generamos de amnera aleatoria, por lo que casos como estos se nos presentan. Se puede solucionar fácilmente este problema si actualizamos el valor del salario para este empleado:


UPDATE empleados SET salario = 60000 WHERE id_empleados = 80;

nuevamente ejecutamos el código para definir el CHECK y ahora no deberíamos tener problemas. Ahora bien, ya hemos definido la restricción CHECK sobre la columna salarios, de esta forma, si intentaramos ingresar un empleado nuevo o actualizar los datos de un empleado y colocar en la columna salario un valor mayor a los 65000 obtendríamos seguramente un error. Comprebemos lo dicho anteriromente


INSERT INTO empleados(nombre, app, apm, puesto, salario, horario) 
    VALUES('Jenny', 'López', 'López', 'Vendedor', 70000, '7:00-10:00');

con lo que obtenemos

Captura3.PNG

un error. Así, estamos garantizando que los registros de la tabla empleados, en especifico los valores de la columna salario, mantenga una integridad de acuerdo a nuestra necesidades. Otro ejemplo de la restricción CHECK es en campos referentes al sexo. Supongamos que en la tabla empleados tenemos una columna destinada al sexo del empleado; para esta columna podríamos definir una restricción CHECK de la siguiente forma


ALTER TABLE empleados ADD CONSTRAINT ck_empleados_sexo 
    CHECK(sexo IN ('Masculino', 'Femenino', 'Otro'))

donde sólo estamos premitiendo que los valores de la tabla empleados en la columna sexo sean Masculino, Femenino u Otros. Así, si llegaramos a ingresar hombre, entonces se nos arrojaría un error.

Otro ejemplo común es agregar una restricción CHECK sobre columnas de números telefónico. Por ejemplo, supongamos que tenemos la columna num_tel en la tabla empleados y deseamos que no sean ingresados números telefónicos con más de 10 cifras, o que lleguen a ingresarse números telefónicos con alguna letra. Entonces emplearemos la siguiente restricción CHECK sobre la columna num_tel


ALTER TABLE empleados ADD CONSTRAINT ck_empleados_num_tel 
    CHECK(num_tel ~ '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')

donde especificamos que el número telefónico debe ser de 10 cifras y cada una de estas cifras será un entero entre el 0 y el 9, además es necesario colocar el símbolo ~ después del nombre de la columna a la cual le aplicares la restricción CHECK. También podemos utilizar intervalos de letras en vez de numéricos (enteros), por ejemplo '[A-Z][A-Z]' indicaría que se debe escribir una palabra conformada de dos letras mayúsculas entre la A y la Z.

Ahora bien, podemos eliminar restricciones CHECK; por ejemplo eliminemos la restricción ck_salario de la tabla empleados


ALTER TABLE empleados DROP CONSTRAINT ck_empleados_salario;

es decir, la sintaxis general para eliminar una restricción CHECK es


ALTER TABLE <<nombre_tabla>> DROP CONSTRAINT ck_<<nombre_tabla>>_<<nombre_columna>>;

Restricción NOT NULL¶

Hay veces en las que no podemos permitir valores nulos dentro de una columna. Por ejemplo, en la tabla empleados, en la columna puesto debemos especificar para cada uno de los empleados el puesto que éstos llevarán a cabo. Así, de manera general, la restricción NOT NULL nos sirve para forzar el ingreso de datos para ciertas columnas.

Para definir esta restricción sobre la columna puesto escribimos


ALTER TABLE empleados ALTER COLUMN puesto SET NOT NULL;

de tal manera, si nosotros intentamos registrar a un empleado nuevo y omitimos el valor correspondiente a la columna puesto, entonces postgres nos arrojará un error:


INSERT INTO empleados(nombre, app, apm, salario, horario) 
    VALUES('Jenny', 'López', 'López', 10000, '6:00-9:00');

Captura4.PNG

Restricción unique¶

Como vimos en la restricción de llave primaria al definirla sobre una columna, dentro de esta columna no se aceptarán valores repetidos. Es decir, si definimos la llave primaria, por ejemplo, sobre el id_empleados de la tabla empleados, entonces no se pirmitirán id's repetidos.

La restricción unique actúa de manera muy similar, pues al definir ésta sobre alguna columna, no se permitirán valores duplicados. Sin embargo, dicha columna no tiene la características principales para ser considerada como llave primaria dentro de esta tabla y además ésta permite valores nulos (lo cual la llave primaria no permite). Por ejemplo, si en la tabla empleados tuvieramos una columna denominada curp, entonces sería necesario definir la restricción unique para dicha columna, lo cual conseguiríamos escribiendo


ALTER TABLE empleados ADD CONSTRAINT uq_empleados_curp UNIQUE(curp);

Observación: El proceso que estamos siguiendo para definir las restricciones no es el mejor, si bien es ilustrativo, éste debe realizarse desde que definimos las tablas y no después como lo estamos haciendo ahora. De tal manera, lo primero que se debe hacer en un proyecto es pensar las tablas que se crearán, pensar las columnas de cada tabla y definir las restricciones sobre las columnas que sean necesarias.

Por ende, la forma en la que estamos llevando el curso es, primero, aprender el código SQL y, después, sobre la marcha ir modificando el proyecto, lo cual es bastante ilustrativo y práctico; sin embargo no es la forma correcta de trabajar, pero, una vez que finalices el curso tendrás de igual manera las herramientas que te peritan trabajar con proyectos de la mejor forma posibble.


Ejercicio¶

  1. Dentro de la tabla productos tenemos distintos productos que vendemos en la papelería. Use el siguiente código


    SELECT DISTINCT nombre_productos FROM productos;
    

    para conocer todos los productos que se venden en la papelería.

    ​ a. Define una restricción CHECK sobre la columna nombre_productos de la tabla productos, basándote en la información que obtuviste de la consulta anterior.

    ​ b. Intenta ingresar un registro que viole la restricción creada en el punto anterior.

    ​ c. Elimina la restricción creada en el punto a.

  2. Elige cualquiera de tus tablas y coloca una restricción de no nulidad en alguna de sus columnas, así como una restricción UNIQUE


Rellenando nuestras tablas con información falsa¶

Hasta el momento, al menos en las tres tablas que trabajamos en clase (empleados, ventas y productos) ya hemos definidos las principales restricciones: las llaves primarias y foráneas. Con lo anterior garantizamos la integridad de nuestros datos y evitamos errores a la hora de ingresar información en cada una de ellas.

Ahora bien, para trabajar de la mejor forma en clases posteriores ingresaremos bastantes filas a nuestras tres tablas base (las que mencionamos antes), lo que nos permitirá introducirnos a manejar bases de datos con muchos registros. Realizaremos pues 1000 inserciones en las tablas empleados, ventas y productos, pero no ingresaremos de forma manual todas esta información, nos auxiliaremos de la página mockaroo para generar las 1000 inserciones. En dicha página se creará de forma aleatoria la información que le pidamos, de acuerdo al tipo de dato de las columnas de nuestras tablas.

Una vez en la página de mockaroo veremos algo como

Captura1.PNG

Primero generaremos la información para las tablas empleados y productos, pues recordemos que en la tabla ventas hay dos columnas con llaves foráneas que depende de la información de estas primeras dos tablas.

Para la tabla empleados.¶

Comenzamos por realizar una consulta


SELECT * FROM empleados;

Captura2.PNG

con base en lo anterior escribimos en mockaroo

Captura3.PNG

es decir, comenzamos colocando el nombre de las columnas de la tabla. Posteriormente agregamos el tipo de dato que le corresponde

Captura4.PNG

agregamos el tipo de dato para las columnas nombre, app, apm buscando en el menú que se despliega de pulsar en las flechas (lo que está en color rojo). En la columna nombre se generarán nombres aleatorios (first name) y en las columnas app, apm se generarán apellidos (last name). Después, trabajaremos con las columnas salario y horario. Para salario, en el menú que se despliega de pulsar la flechas buscaremos la opción number

Captura5.PNG

lo que nos arroja

Captura6.PNG y personalizamos los valores para la columna salario. En nuestro caso colocamos

Captura7.PNG

Después pasamos a la columna horario. Para ello, como le hicimos en la columna anterior, buscamos character sequence, con lo que obtendremos

Captura8.PNG

y después lo personalizamos como

Captura9.PNG

si tienes dudas de porqué colocamos lo anterior puedes pulsar el símbolo de ayuda y mockaroo arrojará una breve guía

Captura10.PNG

Finalmente, en la columna puesto utilizaremos un poco de programación, pues en nuestro caso los puestos de trabajo son muy específicos. Supondremos que sólo hay cuatro puestos de trabajo en la papelería: cajero, vendedor, vigilante y limpieza. Para conseguir asignar a cada uno de los 1000 empleados que generaremos un puesto de trabajo haremos lo siguiente:

  • A cada empleado le asignaremos un número de la siguiente forma: al primer empleado de la tabla le asignamos el 1, al segundo el 2, etcétera. Esto lo conseguimos con row number:

Captura11.PNG

  • Después pulsamos el botón sigma, el cual nos permite escribir código

Captura12.PNG Ahí, la idea será la siguiente:

  1. A los primeros 250 empleados, que tienen asignados los números del 1 al 250 en la columna puesto (lo cual conseguimos al colocar en puesto _row number en mockaroo) les asignaremos el puesto de trabajo de cajero. El código que emplearemos será:
if puesto <= 250 then 'cajero'

es decir, si el número asignado al puesto es menor o igual a 250 entonces escribiremos en la columna puesto cajero.

  1. A los empleados entre el 250 y 500 les asignaremos el puesto de trabajo de vendedor:
elsif puesto <= 500 and puesto > 250 then 'vendedor'

Y el resto queda como

elsif puesto <= 750 and puesto > 500 then 'vigilante'
else 'limpieza' end

En mockaroo tendríamos

Captura13.PNG

pulsamos Apply para aplicar la fórmula del código que escribimos. Después previsualizamos los datos que se generaron. Para ello, en la pestaña principal pulsamos en Preview

Captura14.PNG

donde:

  1. Nos arroja la previsualización de los datos que generamos, en nuestro caso:

Captura15.PNG

  1. Pulsamos en Format y buscamos la opción de sql

Captura16.PNG

una vez seleccionada la opción de SQL nos aparecerá una opción a la derecha denominada Table Name. En ella eliminamos el texto _MOCK_DATA_ y colocamos el nombre de nuestra tabla, la cual es empleados

Captura17.PNG

Finalmente:

  1. Descargamos el archivo .sql pulsando en download data. Es importante saber la ruta donde descargamos dicho archivo.

Ahora bien, realizaremos las 1000 inserciones en la tabla empleados, las cuales tenemos ya en el archivo que descargamos. No obstante, no iremos a pgAdmin para efectuar dichas inserciones pues muy seguramente esto sería muy lento debido al número de inserciones que creamos en el archivo .sql, además podríamos correr el riesgo de que nuestra pc se trabe. Para solucionar esto trabajaremos directamente con postgres. Cabe resaltar que pgAdmin es un cliente postgres, es decir, en él podemos utilizar posgres, siendo así que éste es un intermediario entre el usuario (nosotros) y PostgreSQL.

Para interactuar de manera directa con posgres utilizaremos la consola psql la cual descargamos en conjunto con pgAdmin. Para ello iremos al buscador de aplicaciones y escribimos justamente psql. Después de abrirlo nos debe arrojar la siguiente ventana

Captura18.PNG

en la cual nos dice que estamos trabajando con el servidor local (nuestra pc). Damos enter y nos debe de aparecer

Captura19.PNG

que hace alusión a la base de datos con la cual queremos trabajar. En mi caso, las tablas empleados, ventas, productos se encuentran en una base de datos denominada CursoPostgres, por lo que en

Database [postgres]:

colocaremos CursoPostgres. Después damos enter hasta que nos pide la contraseña que registramos en pgAdmin

Captura20.PNG

una vez ingresada la contraseña damos enter y nos debería de aparecer algo como

Captura21.PNG con lo cual hemos logrado realizar la conexión directa con postgres. De hecho, desde dicha consola (y una vez realizada la conexión) podemos utilizar código sql. Por ejemplo, desde la consola podemos realizar una consulta

Captura22.PNG Ahora bien, cerramos la consola psql y ahora abrimos símbolos del sistema. Ahí, escribiremos


cd C:\Program Files\PostgreSQL\13\bin

En mi caso escribí esa dirección, pero puede que en tu pc dicho archivo tenga otra dirrección y que la versión sea superior a la 13. Para hallar la dirección debes ir a archivos>>este equipo>>Disco local>> archivos de programa y buscar la carpeta PostgreSQL. La abrimos hasta llegar a la carpeta bin , abrimos también esta carpeta y copiamos dicha dirección para después pegarla en la consola

Captura24.PNG

Ahora, en la consola escribimos psql -U postgres -d CursoPostgres -f " " donde colocaremos entre las comillas la dirección donde guardamos el archivo .sql que descargamos de mockaroo:


psql -U postgres -d CursoPostgres -f "C:\Users\weeee\OneDrive\Escritorio\empleados.sql"

Note que escribimos -d CursoPostgres, es decir, después de -d escribimos el nombre de la base de datos que contiene la tabla empleados.

Una vez que damos enter se nos pedirá la contraseña del postgres. Así, cuando damos enter en la contraseña se comenzarán a ejecutar los inserts en la tabla empleados

Captura27.PNG

Así, los inserts se han ejecutado. Después veamos los resultados en pgAdmin

-- Realizamos la consulta
SELECT * FROM empleados;

Primeras 8 filas:

Captura28.PNG

Últimas filas

Captura30.PNG

Para la tabla productos¶

Comenzamos por ver la estructura de esta tabla


SELECT * FROM productos;

Captura1.PNG

Después generamos los datos en mockaroo, en este caso no serán 1000 inserciones, nos bastarán con generar sólo 100 productos de diferentes marcas

Captura2.PNG

es importante ser cauteloso a la hora de generar los datos. Después abrimos la consola psql y realizamos la conexión con postgres

Captura3.PNG

no olvides que en Database [postgres]: debes colocar el nombre de la base de datos que almacena la tabla productos. Luego, vamos a símbolos del sistema para ejecutar las inserciones

Captura4.PNG

una vez ingresada la contraseña tendremos

Captura5.PNG

que las inserciones se han ejecutado. Comprobamos yendo a pgAdmin, recuerda que antes de realizar la consulta debe refrescar (refresh) la tabla o el esquema público


SELECT * FROM productos;

Primeras 8 filas

Captura6.PNG

últimas filas

Captura7.PNG

Notamos que la información, en la mayoría de los casos, no tiene sentido, pero el punto es tener datos para trabajar con ellos.

Finalizamos realizando las inserciones de la tabla ventas, en ella de igual forma sólo efectuaremos 100 inserciones.

Para la tabla ventas¶

Comenzamos por


SELECT * FROM ventas;

Captura8.PNG Hay un detalle en esta tabla. En realidad, de inicio, no construimos bien la tabla ventas pues la columna cantidad está de más. La razón es que, de acuerdo a lo que aprenderemos después, podemos calcular el total de la venta a partir de la columna precio de la tabla productos y de la columna cantidad de la tabla ventas. De tal manera, no es necesario incluir dicha columna en esta tabla. Así, procedemos a eliminar dicha columna. Para ello escribimos


-- Eliminamos la columna total
ALTER TABLE ventas DROP COLUMN total;

-- Vemos los cambios
SELECT * FROM ventas;

Captura9.PNG

Ahora, tenemos otro problema proveniente de la tabla empleados. Si has estado realizando los ejercicios que se dejan en clase, entonces seguramente eliminaste alguna fila de la tabla empleados. Aunque se haya eliminado una fila en dicha tabla, el índice generado en automático por el tipo de dato SERIAL continúa almacenado en dicha tabla, de tal manera, la fila siguiente a la fila eliminada tendrá como id el número sucesor de la fila eliminada. Por ejemplo, en mi caso

Captura10.PNG

eliminé la fila 3, no obstante, el índice del id_empleados excluye de la numeración al número 3. Ahora bien, el problema radica en la columna id_empleado de la tabla ventas pues, si ingresamos en dicha columna el número 3, entonces postgres nos arrojará un error referencial debido a la llave foránea definida en dicha columna. Para resolver el problema

  • Ingresamos en mockaroo una fórmula (código) para que se excluya el número 3.

De donde

Captura11.PNG

y en la fórmula escribimos

Captura13.PNG

Una vez descargado el archivo vamos a símbolos del sistema para efectuar las inserciones

Captura14.PNG

Captura15.PNG

y vemos en pgAdmin la actualización de la tabla ventas

SELECT * FROM ventas;

Captura16.PNG

y los últimos registros

Captura17.PNG


Generando datos aleatorios utilizando Python (Opcional)¶

Supuestos:¶
  • El alumno tiene conocimientos básicos de Python.

Para realizar lo siguiente, puedes utilizar las libretas de Python en google colab.


Lo que haremos primero será instalar la librería Faker, la cual nos permite generar información falsa. Para ello

In [1]:
# Instalamos la libreria
!pip install Faker
Requirement already satisfied: Faker in c:\programdata\miniconda3\lib\site-packages (15.3.3)
Requirement already satisfied: python-dateutil>=2.4 in c:\programdata\miniconda3\lib\site-packages (from Faker) (2.8.2)
Requirement already satisfied: six>=1.5 in c:\programdata\miniconda3\lib\site-packages (from python-dateutil>=2.4->Faker) (1.16.0)

Cargamos las librerías a utilizar y damos un vistazo a algunas funciones de dicha librería

In [4]:
# Datos falsos
from faker import Faker
# Numeros y selecciones aleatorias
import random
# impresion mas bonita
import pprint

# Configuramos la libreria faker para generar datos en español (Mexico)
fake = Faker(['es_MX'])

# diccionario donde guardaremos toda la info
info = dict()

# Para generar una edad:
# generamos un numero aleatorio entero entre el 18 y 90
edad = random.randint(18, 90)
info['edad']  = edad

# Para el sexo, definimos una lista
sexo = ["M", "F", "O"]

# Con la libreria random podemos hacer una seleccion aleatoria de la lista
# sexo mediante la funcion choice()
sexo1 = random.choice(sexo)
info['sexo']  = sexo1

# Para el sueldo (0,1)
# Con la funcion random() generamos un numero aletorio decimal en el
# intervalo (0,1)
# 0.6879878789 * 10000 = 6879.878789---->6879.87
sueldo = round(random.random() * random.randint(1000, 100000),2)
info['sueldo']  = sueldo

# generamos un nombre aleatorio
nombre = fake.name()
info['nombre']  = nombre

# una direccion
direc = fake.address()
info['dirección']  = direc

# un trabajo
trabajo = fake.job()
info['trabajo']  = trabajo

# una ciudad
ciudad = fake.city()
info['ciudad']  = ciudad

# un curp
curp = fake.curp()
info['curp']  = curp

# Veamos hasta el momento toda la informacion que generamos
pprint.pprint(info)
{'ciudad': 'San Manuel de la Montaña',
 'curp': 'BUYN570418MVZBCY09',
 'dirección': 'Prolongación República de Moldova 158 Edif. 909 , Depto. 661\n'
              'Nueva Países Bajos, HGO 28192-9641',
 'edad': 28,
 'nombre': 'Bianca Espartaco Badillo Prieto',
 'sexo': 'F',
 'sueldo': 40607.08,
 'trabajo': 'Empleado de biblioteca'}

Ahora bien, supongamos que queremos obtener información para la tabla productos, de modo que queremos obtener información para las columnas id_productos, cantidad_almacen, precio, nombre_productos. Para ello podríamos generar

In [9]:
# simulacion de la info para 5 filas
productos = ["Lapiz", "Goma", "Cartulina", "Colores"]

for id in range(1,6):
    # info
    cantidad_almacen = random.randint(0,100)
    precio = round(random.random() * random.randint(1,1000),2)
    nombre_produtos = random.choice(productos)
    # instruccion
    cadena = f"INSERT INTO productos VALUES ({cantidad_almacen}, {precio}, '{nombre_produtos}');"
    # mostramos
    print(cadena)
INSERT INTO productos VALUES (41, 626.63, 'Colores');
INSERT INTO productos VALUES (16, 465.09, 'Goma');
INSERT INTO productos VALUES (88, 65.95, 'Cartulina');
INSERT INTO productos VALUES (58, 291.06, 'Colores');
INSERT INTO productos VALUES (11, 199.46, 'Lapiz');

Donde, con dichos inserts, ya podríamos ejecutarlos en pgAdmin. Podríamos copiar dichos inserts y después pegarlos en alguna Query tool en pgAdmin, no obstante, lo que haremos será crear un archivo que tenga todos los inserts y después lo ejecutaremos utilizando la consola, así como hicimos con los datos generados en Mockaroo. Para ello

In [11]:
# Creamos un archivo txt
inserts = open("DatosPython.txt","w") 

# lista de productos
productos = ["Lapiz", "Goma", "Cartulina", "Colores", "Plumas", "Cuadernos"]

# Obtendremos 100 registros
for id in range(1,101):
    # info
    cantidad_almacen = random.randint(0,100)
    precio = round(random.random() * random.randint(1,1000),2)
    nombre_produtos = random.choice(productos)
    # instruccion
    cadena = f"INSERT INTO productos VALUES ({cantidad_almacen}, {precio}, '{nombre_produtos}');"
    # escribiremos la cadena de texto anterior en el archivo txt
    inserts.write(cadena)
    # Salto de linea en el archivo txt
    inserts.write("\n")
# Cerramos el archivo txt
inserts.close() 

Dicho archivo se descargará en automático, después lo abrimos y lo guardaremos como un archivo .sql aux1002.PNG

Una vez que ya tenemos dicho archivo (y sabemos la ubicación en la que se encuentra), procedemos a realizar el mismo proceso en consola como lo vimos antes.

Adicionalmente, si queremos otro tipo de información para nuestras tablas, podemos utilizar, como se vio, la librería Faker, recordemos que

In [12]:
pprint.pprint(info)
{'ciudad': 'San Manuel de la Montaña',
 'curp': 'BUYN570418MVZBCY09',
 'dirección': 'Prolongación República de Moldova 158 Edif. 909 , Depto. 661\n'
              'Nueva Países Bajos, HGO 28192-9641',
 'edad': 28,
 'nombre': 'Bianca Espartaco Badillo Prieto',
 'sexo': 'F',
 'sueldo': 40607.08,
 'trabajo': 'Empleado de biblioteca'}

por lo que podríamos generar nombres, CURPS, direcciones falsas, entre otros más.

Aquí otro ejemplo (se requieren conocimientos en las librerías SQLite y Pandas) a la hora de generar información falsa Libreta en google colab


Ejercicio¶

De las tablas adicionales que creaste (es decir aquellas tablas que no son empleados, productos, ventas) en la base de datos (referente al proyecto). Crea las inserciones utilizando cualquiera de los dos métodos que vimos en esta clase, es decir, generando los datos en Mockaroo o en Python.