En la incansable búsqueda por conseguir hacer que las cosas funcionen lo mejor posible, me he encontrado con un plugin que vengo a compartir en este post. Se trata un plugin que todo desarrollador de WordPress debería de conocer, el Query Monitor.
Es un plugin que una vez instalado te muestra detalladamente qué es lo que está pasando dentro de WordPress para poder depurar, mejorar todo y aumentar el rendimiento de la web. Es una manera de tener una visión global del funcionamiento, número de consultas a la base de datos, plantillas cargadas, tiempos, errores/notificaciones/advertencias en la programación, y un largo etcétera..
¡Hola de nuevo! Como siempre que puedo, trabajo con Open Source, pues aquí que sigo con la filosofía del Open Source, compartiendo algo más de código fuente Open Source. La verdad es que nunca me planteo alternativas que no sean Open Source, con lo que tengo incluso la obligación de compartir códigos Open Source, ya que tanto me beneficio de los proyectos Open Source, en lo laboral y en lo personal, valga la redundancia.. Se nota que me gusta el Open Source ¿verdad? xDDD
Continuando con el post anterior sobre los índices de Magento, dejo aquí unas pocas explicaciones por si a alguien le sirve de cómo funcionan las tablas de reindex por dentro. El post anterior introducía el concepto de los índices de Magento, qué son, para qué sirven. Vamos a ver un poco más con unos casos de uso.
Hoy traigo otro code-kata, esta vez para Magento y hecho en PHP. Se trata de un simple script que se lanza en línea de comandos. Con este script obtendremos primero todos los métodos de pago que se han usado al hacer los pedidos. Después, haremos un listado, por método de pago, y entre ciertas fechas, del monto de pedidos completados por método de pago.
Es decir, supongamos que queremos saber cómo han ido las ventas con el método de pago por tarjeta de crédito. O quizá queremos saber si la financiación es un método de pago que funciona bien. O quizá simplemente queremos tener el total de ventas entre fechas.
Pues todo esto es bastante sencillo sabiendo donde está cada cosa.
Métodos de pago usados en pedidos
A saber, los pedidos en Magento 1 guardan parte de sus datos principales en la tabla sales_flat_order. La información del método de pago utilizado en cada pedido se guarda en la tabla sales_flat_order_payment.
Entonces, sacando la columna method de la tabla sales_flat_order_payment tendremos todos los métodos de pago utilizados en los pedidos. Esto en lenguaje SQL queda así:
SELECT distinct(sfop.method)
FROM sales_flat_order_payment sfop
ORDER BY sfop.method ASC;
Ventas de los pedidos enviados
El siguiente paso será saber cómo sacar las cantidades de los pedidos completados. A saber, los pedidos completados se quedan con un status=complete y state=complete. Sí, es raro, Magento tiene internamente dos estados en cada pedido. Uno llamado status y otro llamado state. Estos estados están respectivamente en sus columnas. Así la consulta a la base de datos en SQL para sacar las ventas de un método de pago queda así:
SELECT sum(sfo.grand_total) total_sold
FROM sales_flat_order sfo
JOIN sales_flat_order_payment sfop ON sfop.parent_id = sfo.entity_id
WHERE sfo.state = 'complete' AND sfo.state = 'complete' AND sfop.method LIKE '".$methodCode."'
AND sfo.created_at > '".$startDate->format('Y-m-d H:i:s')."'
AND sfo.created_at < '".$endDate->format('Y-m-d H:i:s')."'"
Fíjate que la tabla sales_flat_order_payment se relaciona con sales_flat_order de la forma que marco en negrita.
El código completo
Ahora bien, haciendo un poco de ejercicio con un par de bucles, programando el script completo, nos queda algo tal que así:
<php
require_once __DIR__.'/app/Mage.php';
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
// Loading arguments.
if ($argc == 3) {
$yearFrom = $argv[1];
$yearTo = $argv[2];
} else {
echo 'ERROR: Incorrect number of arguments.'.PHP_EOL;
exit;
}
$sqlConnection = Mage::getSingleton('core/resource')->getConnection('core_read');
// Loading available method codes.
$query = 'SELECT distinct(sfop.method)
FROM sales_flat_order_payment sfop
ORDER BY sfop.method ASC;';
$methods = $sqlConnection->fetchAll($query);
$methodCodes = array();
foreach ($methods as $method) {
$methodCodes[] = $method['method'];
}
//var_dump($methodCodes);
// Printing table in CSV format from January to December..
echo 'PAYMENT_METHOD';
for ($year = $yearFrom; $year <= $yearTo; ++$year) {
for ($month = 1; $month <= 12; ++$month) {
echo ','.$year.$month;
}
}
echo PHP_EOL;
foreach ($methodCodes as $methodCode) {
echo $methodCode;
for ($year = $yearFrom; $year <= $yearTo; ++$year) {
for ($month = 1; $month <= 11; ++$month) {
$startDate = new DateTime($year.'-'.$month.'-1 00:00:00');
//echo 'Date from: '.$startDate->format('Y-m-d H:i:s').PHP_EOL;
$endDate = new DateTime($year.'-'.($month + 1).'-1 00:00:00');
//echo 'Date to: '.$endDate->format('Y-m-d H:i:s').PHP_EOL;
$query = "SELECT sum(sfo.grand_total) total_sold
FROM sales_flat_order sfo
JOIN sales_flat_order_payment sfop ON sfop.parent_id = sfo.entity_id
WHERE sfo.state = 'complete' AND sfo.state = 'complete' AND sfop.method LIKE '".$methodCode."'
AND sfo.created_at > '".$startDate->format('Y-m-d H:i:s')."'
AND sfo.created_at < '".$endDate->format('Y-m-d H:i:s')."'";
$amount = $sqlConnection->fetchOne($query);
echo ','.$amount;
}
$startDate = new DateTime($year.'-12-1 00:00:00');
//echo 'Date from: '.$startDate->format('Y-m-d H:i:s').PHP_EOL;
$endDate = new DateTime($year.'-12-31 23:59:59');
//echo 'Date to: '.$endDate->format('Y-m-d H:i:s').PHP_EOL;
$query = "SELECT sum(sfo.grand_total) total_sold
FROM sales_flat_order sfo
JOIN sales_flat_order_payment sfop ON sfop.parent_id = sfo.entity_id
WHERE sfo.state = 'complete' AND sfo.state = 'complete' AND sfop.method LIKE '".$methodCode."'
AND sfo.created_at > '".$startDate->format('Y-m-d H:i:s')."'
AND sfo.created_at < '".$endDate->format('Y-m-d H:i:s')."'";
$amount = $sqlConnection->fetchOne($query);
echo ','.$amount;
}
echo PHP_EOL;
}
Este script tendremos que ponerlo en el directorio raiz del proyecto Magento para que enganche al Magento. Fíjate que necesita de dos parámetros de entrada que son el año de inicio y el año de fin. Además he marcado un objeto que proporciona Magento para estas cosas, la conexión a la base de datos que se guarda en $sqlConnection.
Ejecutando
Guardamos el script anterior en un fichero, por ejemplo llamado script.php. Si queremos las ventas desde el año 2017 al 2017, lo ejecutamos así desde línea de comandos:
$ php script.php 2017 2017
Veremos la salida por pantalla. Ahora bien, si redireccionamos la salida del script a un fichero, luego podremos visualizarlo mejor. Para esto lo ejecutamos así:
Así jugando un poco con los datos resultantes, podemos tener una gráfica de evolución de los métodos de pago. Como la imagen de cabecera de arriba. Podemos ver que algo está pasando en abril y por Navidades del año 2017 con uno de los métodos de pago.
Una de las bondades que tienen Magento es su flexibilidad. En este post vamos a ver el tema de los atributos de producto, cual es su scope o alcance. En general, esto se facilita mucho con su uso interno del modelo de datos EAV. Gracias a EAV que podemos gestionar muchos valores de atributos de cada elemento sin tener que modificar la base de datos. Es decir, no tenemos que hacer una columna nueva para cada atributo nuevo. Sino que se da de alta el atributo en una tabla, y en otra se guardan los valores de los atributos sin haber hecho absolutamente ninguna modificación en la estructura de la base de datos.
Disponemos de tres niveles de configuración normalmente, aunque realmente hay cuatro, para configurar muchas de las cosas que hay dentro de un Magento. Tenemos el nivel de website, de store y de store view. Traducidos son sitio web, tienda, y vista de tienda; y además tenemos el nivel global. Por ejemplo, si vamos a las configuraciones de tiendas podemos tener varios nombres de dominio (uno por website), cada uno con sus configuraciones, plantillas distintas, productos distintos, incluso clientes distintos asignados a cada website o compartidos entre todos los websites. Dentro de un website podemos tener varias tiendas o stores. Y de cada tienda podemos tener varias vistas de tienda, incluso pudiendo cambiar las plantillas o muchas de sus configuraciones de productos, categorías, etc..
El caso de los productos
Volviendo a los productos, primero tenemos que los podemos asignar a cada website. Es decir, un producto puede publicarse en uno de los websites mientras que en otro no. Si vamos al listado de productos nos encontramos en un Magento 1.9 arriba con un desplegable como el de la imagen de al lado, donde podemos configurar los productos a nivel de store view.
Los productos se trabajan al más bajo nivel, al de store view. Esto es así porque el nivel de store view se suele usar para traducir la web. Es decir, publicamos un producto en un website, y configuramos a nivel de vista de tienda cómo lo va a ver el usuario. Si tenemos una vista de tienda por cada idioma, podremos configurar su nombre, descripción, características, etc.. traduciéndolas para cada idioma.
El nivel de los atributos de producto
Podemos dar de alta y configurar nuevos atributos, en la zona de gestión de atributos. Un listado de atributos de ejemplo podría ser tal que así:
Si el valor del atributo es el mismo en todas las tiendas o vistas de tienda, entonces debería de ser global. Si el valor es distinto, traducible para cada store view, debe de tener el nivel de store view. Es importante saber que todas las etiquetas que se muestran siempre se pueden traducir para cada store view, independientemente de los valores que tome dichos atributos. Es decir, no confundamos las etiquetas que podemos traducirlas con los valores que también podemos traducirlos, no te lleve a confusión.
El atributo de producto ‘status’ es de sistema
Todos los atributos del listado anterior no son de sistema, con lo que no tienen limitación para configurarlos como queramos. Pero los de sistema sí que están limitados. Para este post vamos a trabajar con un atributo que ya viene configurado en Magento que es el estado (status). El estado puede estar habilitado o deshabilitado, y viene configurado a nivel de sitio web. Este atributo puede configurarse para que esté a nivel de website o nivel global. Si lo tenemos a nivel de website entonces podremos habilitar o deshabilitar un producto independientemente en cada website de nuestro Magento.
Esta flexibilidad está bien, pero sólo en ciertos casos. Si tenemos varios websites, de cada uno por lo menos una store, y dentro de cada store podemos tener varias store views para traducir las tiendas.. se puede reducir la cantidad de configuraciones si ponemos el nivel adecuado para cada atributo. Volviendo al caso del atributo status, si me interesa que cuando deshabilite un producto lo haga para todos los websites, entonces debemos de tenerlo a nivel global. De lo contrario, si tenemos 3 sitios web, para estar seguros de que deshabilitamos o habilitamos correctamente el productos en todos los websites deberemos de entrar en la configuración de producto varias veces y comprobarlo.
Así que vamos a ponerlo a nivel global y asegurarnos de que no quedan valores personalizados a nivel de website. Y en tal caso los borramos. Así evitaremos esta excesiva navegación por las fichas de producto. Y así nos aseguramos de que un producto deshabilitado, lo está realmente en todos los websites.
Finalmente, pasando a global el atributo status
Entramos en la configuración del atributo y lo modificamos para que sea global:
Sólo nos falta entrar a la base de datos y, en este caso, borrar todas las configuraciones del atributo a nivel de website que se hayan hecho para que sólo se aplique la configuración global en cada producto. Si se nos quedara en la base de datos algún valor personalizado sin borrar, Magento cogería dicho valor personalizado, en caso de no encontrar valores personalizados de nivel más bajo entonces cogería el valor global.
Encontrando el identificador del atributo
Para esto no tenemos más que entrar a la base de datos e ir a la tabla eav_attribute. Aquí tenemos definidos los atributos que gestionamos en el panel de control. De forma que, tenemos dos columnas con las que identificamos el atributo status: la columna attribute_code, y la columna attribute_id. Aquí buscamos el código que le hemos puesto al atributo, en este caso ‘status’, que no lo hemos creado nosotros porque es de sistema y ya viene configurado.
Ya hemos encontrado el identificador del atributo, que es el 96. Ahora ya podemos ir a revisar los valores que ha ido tomando el atributo para las distintas vistas de tienda. Para esto vamos a la tabla catalog_product_entity_int que es donde se guardan los ‘valores enteros de los atributos de entidades de productos’ como su nombre indica en inglés.
Como podemos ver en la imagen, el atributo 96 está cogiendo los valores 1, 2.. para el status el valor 1 es de producto habilitado, el 2 es deshabilitado. Según vemos en la imagen y haciendo un par de consultas podemos ver que la store_id es cero siempre en mi caso. A saber, la store_id cero es el valor del atributo global, es el que coge Magento en caso de encontrar ninguno personalizado. Si tenemos guardados valores distintos para las vistas de tienda, entonces habrían valores con store_id distintos, donde cada store_id corresponde con el identificador de la store.
Cómo listar los stores de una tienda lo cité en el post este, en donde se listan primero los store_id para luego ir recorriendo los productos y asignándolos a todas las stores. Podemos coger aquel script y listar los store_id y así poder editar o simplemente borrar las configuraciones de algunas de las stores.
Borrando valores de atributo personalizados
En este caso, si quisiéramos borrar todas los valores de status personalizados en cada store view bastaría con ejecutar la consulta siguiente y vemos si hay dichos valores personalizados:
SELECT * FROM magento_maxmovil.catalog_product_entity_int
WHERE attribute_id = 96 AND store_id != 0;
Si los hay simplemente modificamos la anterior consulta para borrarlos:
DELETE FROM magento_maxmovil.catalog_product_entity_int
WHERE attribute_id = 96 AND store_id != 0;
Con esto ya nos aseguramos que no vaya a haber problema y hemos pasado el atributo status a scope global. Esto mismo se puede hacer para cualquier otro atributo.
Con esto queda terminado 🙂 otro día más 😉 Un saludo!
Ya estoy de nuevo por aquí frikeando un poco con el software. Estoy en estos días poniéndome al día con Magento. Es la gran solución de Código Libre para trabajar de forma económica montando una web. Entre las tres principales soluciones es la que de momento ostenta la primera posición, la segunda viene a ser Prestashop y la tercera WooCommerce.
Estoy hablando de las soluciones económicas, Open Source, PHP, robustas y estables. Ya si nos centramos sólo en España veremos que el despunte de tiendas online es para Prestashop. Espero no equivocarme con los datos, los puedes comprobar rápidamente haciendo un par de búsquedas y dejar un comentario abajo para corregir.
Situación
Resulta que tenemos entre manos ahora un Magento, pero no podemos entrar al panel de administración que lo tenemos en: https://nombredominio.com/index.php/admin
Pero sí que tenemos acceso a la base de datos. Es imprescindible tenerlo porque si no entonces tendremos que descartar éste mecanismo de recuperación. Necesitamos entonces acceso mediante phpMyAdmin, Mysql Workbench, línea de comandos..
Dónde tenemos que tocar
Ahora bien, los administradores están en la tabla admin_user y la contraseña de cada uno es la columna password. Si le hemos puesto un prefijo a las tablas entonces la tabla será de la forma prefijo_admin_user. Jeje, parece fácil pero ahora bien ¿qué cifrado se usa en Magento? Pues MD5, y se le añade una semilla al cifrado para hacerlo mejor.
Cómo cifra Magento las claves de administrador
Resumiendo, la estrategia es que pone una semilla delante de la contraseña. Si por ejemplo la semilla va a ser la palabra ‘semilla’ y la contraseña ‘thepass’ lo que hace es cifrar con MD5 la cadena ‘semillathepass’ y luego al resultado le añade después ‘:semilla’ y lo guarda.
Simplemente tenemos que ejecutar lo siguiente que hace esto que explico aquí arriba en el cliente de la base de datos Mysql y tendremos entonces la contraseña cambiada: UPDATE basededatos.prefijo_admin_user SET password=CONCAT(MD5(‘semillathepass’), ‘:semilla’) WHERE username=’administrador’;
Simplemente ejecutamos esto y se actualizará la clave del administrador ‘administrador’ poniéndole de clave ‘thepass’. Ya lo modificas a tu gusto y a correr 😉
¿Y las claves de usuarios clientes de la tienda?
Ahora bien, vamos a ir un paso más allá. Porque ¿dónde están las claves de los clientes? Éstas las tenemos en la tabla prefijo_customer_entity_varchar, y en prefijo_customer_entity tenemos los valores principales de los usuarios. Y en mi instalación estoy viendo que el atributo de identificador 12 corresponde a las claves de clientes. Que a su vez están cifradas de forma similar a las de administrador.
¿Pero qué tenemos aquí? ¿Porqué tenemos tantas tablas? ¿No sería mas sencillo una supertabla con una fila para cada usuario? Lo que ocurre es que Magento usa el modelo de datos EAV. Es un modelo de datos con el que los atributos que van a tener unos elementos se definen en una tabla, en otras se definen los principales valores de dichos elementos, y los valores disponibles se definen en otra tabla. Esto es engorroso para programar pero proporciona que se puedan definir en ejecución tantos valores como queramos de forma de que no se tengan que modificar ni códigos fuentes ni base de datos. Es muy potente, flexible, pero es engorroso y aumenta la complejidad.. a la hora de tocar base de datos o hacer consultas.
Es muy sencillo verlo de la siguiente forma. Tenemos la tabla de atributos prefijo_eav_attribute, si vemos un listado de algunos atributos podemos tener algo tal que así:
Fíjate que el atributo 12 es el password_hash. Ahora si vamos a los atributos de los customers que tenemos en la tabla prefijo_customer_entity_varchar y vemos los valores de las filas con attribute_id que sea 12 veremos que se parecen a contraseñas como las de los administradores ¿verdad?
Jeje, pues ya tenemos ahí las contraseñas. Parece que tenemos también la semilla después de los dos puntos concatenada con la clave. Será fácil entonces hacer otra consulta que actualice la contraseña de los usuarios de igual manera que la de los administradores.
UPDATE basededatos.prefijo_customer_entity_varchar SET password=CONCAT(MD5(‘semillathepass’), ‘:semilla’) WHERE value_id=1030;
Esta última consulta se supone que modificará la contraseña del cliente con identificador 175, es el valor 1030. A su vez el cliente que tendrá su email en la tabla prefijo_customer_entity y otros datos repartidos por sus tablas correspondientes.
Terminando
Ya lo dejo aquí, con el modelo de datos EAV, que es muy potente, tendremos disponibles todos los datos y podremos andar modificando no sólo las contraseñas de los clientes. Habrá que tener especial cuidado de no sobrecargar de consultas la base de datos, o hacerlo bien optimizándolas con JOINs en vez de concatenando tablas, no creando demasiados bucles que consultan datos y a su vez vuelven a consultar más datos con los resultados, etc.. porque fácilmente podemos relentizar en funcionamiento de nuestro Magento. Pero por otro lado tendremos un sistema muy potente para ir añadiendo lo que necesitemos si crear más y más tablas cada 2 por 3, con el consecuente peligro a la hora de actualizar cuando se añaden tablas o se modifica la base de datos.
En estos días he estado haciendo una copia de seguridad de una base de datos compatible con MySQL. En concreto de MariaDB, un ‘replace’ que funciona muy pero que muy bien. Para éste ejemplo he usado un servidor Linux, supongo que en otros sistemas operativos también tendremos disponibles estos comandos.
MariaDB es un fork de la conocida base de datos MySQL que ha seguido más y más desarrollándose e incorporando más y más funcionalidades.
Vamos al grano, es sencillo exportar a un fichero SQL desde línea de comandos con un comando como el siguiente: $ mysqldump nombreBaseDeDatos -uuser -ppassword > nombreFichero.sql
Lo que hay después de -u es un nombre de usuario, después de -p la contraseña, debe ser un usuario y contraseña válidos y que tengan permiso de acceso a toda la base de datos.
Si queremos hacer pruebas antes de guardar a un fichero el contenido podemos omitir lo último del comando para ver lo que hay en la BD.
$ mysqldump nombreBaseDeDatos -uuser -ppassword
A continuación, si queremos importar el fichero SQL ejecutamos lo siguiente en línea de comandos:
$ mysql nombreBaseDeDatos -uuser -ppassword < nombreFichero.sql
Hoy les dejo un acceso a una base de datos SQLite, que últimamente está tan de moda. SQLite se usa en todo tipo de programas, es de dominio público, se puede incluir en tu programa añadiendo alguna librería muy ligera, y te da casi todas las funcionalidades que te puede dar cualquier otra BD relacional (de las que usan SQL).
Materiales
Una vez más, mi entorno de desarrollo favorito, el Eclipse que supongo ya instalado. También se puede seguir el post usando otro entorno http://www.eclipse.org/
Lo que he averiguado en mis investigaciones, más que nada con lo que me han explicado amigos, es que SQLite lo que no tiene son claves ajenas, con lo que la integridad referencial no está implementada dentro de su llamemosle «motor de la BD» es que tenemos integridad referencial, claves ajenas. Se pueden usar disparadores (triggers), cuando se hagan inserciones, modificaciones o borrados. Podemos usar BLOBs, definir los tipos de datos de las tablas, y un largo etcétera…
Según pone en la Wikipedia http://es.wikipedia.org/wiki/SQLite, la versión 3 de SQLite admite archivos de 2 Terabytes con incluso tipos de datos BLOB, con lo que podemos almacenar ficheros dentro de la base de dato. Con ésto creo que tenemos bastante, por lo menos para empezar a trastear las BD sin tener que instalar todo un señor motor de BD como los de Oracle o MS SQL Server, o los que más me gustan a mi como PostgreSQL o Firebird. En Java funcionan todas éstas BD de manera parecida, la idea principal es usar el JDBC que proporciona un estándar de conexión para conexión a bases de datos desde Java.
Manos a la obra
Al grano, después de un poco de teoría, antes de empezar con el código, hay que preparar el proyecto en Eclipse:
Creo un nuevo proyecto de Java.
Copio la librería de SQLite, en el proyecto, Eclipse te deja coger y arrastrar el fichero al Explodor de Proyectos con lo que te proguntará si quieres copiar o hacer un enlace externo al fichero. Prefiero copiarlo dentro del proyecto porqué así siempre estará incluido si es que creamos un ejecutable o nos llevamos el proyecto a otro ordenador.
No basta con copiar la librería, tenemos que agregarla al Build Path del proyecto. Con el botón derecho del ratón en el explorador de proyectos, le damos a Build Path > Configure Build Path… Le damos a Add JAR… y elegimos el fichero que ya está dentro del proyecto. Debes ver una ventana parecida a ésta:
Hecho ésto ya podemos usar la librería desde cualquier clase que creemos dentro de éste proyecto. Entonces ya sí que sí, que empezamos creando una nueva clase, con un main. Yo he usado el generador de código de Eclipse y me ahorro tiempo. Entonces el código de ejemplo con el que se crea un fichero bdpruebas.db, luego dentro crea una tabla llamada tablapruebas, y va insertando valores aleatorios del 1 al 100 con un índice. Queda así:
// CREAR UNA TABLA NUEVA, LA BORRA SI EXISTE enunciado.execute("DROP TABLE IF EXISTS tablapruebas;"); enunciado.execute("CREATE TABLE tablapruebas (id int primary key, aleatorio int);");
// INSERTAR DATOS for (int i = 1; i <= 100; i++) { enunciado.execute("INSERT INTO tablapruebas (id, aleatorio) values (" + i + ", " + Math.floor(Math.random() * 100 + 1) + ");"); }
// CONSULTA DATOS ResultSet resultados; resultados = enunciado.executeQuery("SELECT * FROM tablapruebas;");
// PROCESAR EL RESULTADO while (resultados.next()) { System.out.println("id " + resultados.getString(1) + ": aleatorio " + resultados.getString(2)); }
Lo que hace el código es crear tres objetos: conexión, enunciado y resultados. Con conexión como su nombre indica, nos conectamos a la base de datos, si el fichero no existe lo crea, ésto es un comportamiento propio de SQLite. Con el enunciado lo que venimos a tener es una especie de «mesa de trabajo» con lo que vamos a atacar la base de datos con todo tipo de consultas o sentencias SQL. Es interesante el PreparedStatement para mejorar el funcionamiento interno de nuestro programa pero eso es otro tema. Luego con el objeto resultados en éste ejemplo lo que se hace es almacenar los resultados de la consulta.
Las sentencias SQL que se han usado lo que hacen es borrar la tabla si existe, la crean y llenan la tabla con los INSERT INTO. La última consulta con el SELECT lo que hace simplemente es listar todos los resultados de la tabla.
Dejo el proyecto en descarga como viene siendo costumbre xD
Para terminar, si pulsamos F11 en la ventana de consola debemos ver en los resultados algo tal que así:
id 1: aleatorio 4 id 2: aleatorio 70 id 3: aleatorio 94 id 4: aleatorio 40 id 5: aleatorio 86 id 6: aleatorio 40 id 7: aleatorio 89 id 8: aleatorio 80 id 9: aleatorio 79 id 10: aleatorio 14 id 11: aleatorio 69 id 12: aleatorio 2 id 13: aleatorio 12 id 14: aleatorio 62 id 15: aleatorio 74 id 16: aleatorio 53 id 17: aleatorio 45 id 18: aleatorio 44 id 19: aleatorio 56 id 20: aleatorio 40 id 21: aleatorio 81 id 22: aleatorio 75 id 23: aleatorio 97 id 24: aleatorio 78 id 25: aleatorio 63 id 26: aleatorio 30 id 27: aleatorio 13 id 28: aleatorio 21 id 29: aleatorio 68 id 30: aleatorio 58 id 31: aleatorio 25 id 32: aleatorio 92 id 33: aleatorio 88 id 34: aleatorio 77 id 35: aleatorio 38 id 36: aleatorio 45 id 37: aleatorio 18 id 38: aleatorio 47 id 39: aleatorio 60 id 40: aleatorio 51 id 41: aleatorio 90 id 42: aleatorio 90 id 43: aleatorio 96 id 44: aleatorio 34 id 45: aleatorio 47 id 46: aleatorio 89 id 47: aleatorio 97 id 48: aleatorio 58 id 49: aleatorio 78 id 50: aleatorio 49 id 51: aleatorio 23 id 52: aleatorio 82 id 53: aleatorio 12 id 54: aleatorio 92 id 55: aleatorio 51 id 56: aleatorio 99 id 57: aleatorio 56 id 58: aleatorio 9 id 59: aleatorio 14 id 60: aleatorio 1 id 61: aleatorio 4 id 62: aleatorio 80 id 63: aleatorio 80 id 64: aleatorio 97 id 65: aleatorio 89 id 66: aleatorio 47 id 67: aleatorio 3 id 68: aleatorio 73 id 69: aleatorio 34 id 70: aleatorio 99 id 71: aleatorio 22 id 72: aleatorio 38 id 73: aleatorio 69 id 74: aleatorio 22 id 75: aleatorio 6 id 76: aleatorio 97 id 77: aleatorio 28 id 78: aleatorio 47 id 79: aleatorio 21 id 80: aleatorio 50 id 81: aleatorio 89 id 82: aleatorio 22 id 83: aleatorio 71 id 84: aleatorio 98 id 85: aleatorio 45 id 86: aleatorio 20 id 87: aleatorio 12 id 88: aleatorio 29 id 89: aleatorio 75 id 90: aleatorio 11 id 91: aleatorio 54 id 92: aleatorio 24 id 93: aleatorio 86 id 94: aleatorio 89 id 95: aleatorio 90 id 96: aleatorio 39 id 97: aleatorio 34 id 98: aleatorio 1 id 99: aleatorio 37 id 100: aleatorio 66
Ya les dejo con ésto, espero que a alguien le sirva, un saludo.