Introducción
MEND & MOSS repara artículos del hogar. Dos proveedores usan el SKU BOLT-1, pero venden pernos diferentes. La tienda conserva una nota local de ubicación junto con el nombre, el precio y la revisión de cada proveedor. Una revisión es un número de edición positivo: cuanto mayor es, más reciente es la edición.
En este laboratorio guiado, cargarás un CSV de proveedor de seis líneas en una tabla intermedia sin modificar las existencias y crearás vistas SQL reutilizables que separen los registros utilizables de los no válidos. Una vista es una consulta guardada, no una segunda copia de sus filas. Solo necesitas conocimientos básicos para moverte por la terminal; las instrucciones SQL y los comandos de SQLite se presentan antes de usarlos. Todos los registros de la tienda son sintéticos.
Usa la pestaña Terminal durante todo el laboratorio. SQLite y la base de datos inicial están preparados. No hay ningún sitio web que construir. Mantén sin cambios las existencias originales y los dos archivos de deliveries/.
Consultar las existencias y cargar una entrega
En este paso, relacionarás un registro normal de existencias con su proveedor e importarás la entrega actual completa a una tabla intermedia independiente. Empieza en Terminal. cd cambia de directorio; esta ruta absoluta también permite recuperarte de un error común de directorio incorrecto:
cd /home/labex/project/supplier-desk
ls enumera los archivos. Deberías ver stock.db y deliveries:
ls
La base de datos es un archivo real. sqlite3 stock.db lo abre en el intérprete interactivo de SQLite. Permanece en el indicador sqlite> para introducir las instrucciones SQL y los comandos de punto siguientes; no los escribas en el indicador del intérprete de Linux:
sqlite3 stock.db
Una tabla almacena filas en columnas con nombre. SELECT elige las columnas que se leerán, FROM indica una tabla y ORDER BY establece un orden de visualización predecible. Las instrucciones SQL terminan en ;. Los dos comandos de punto controlan la presentación: .headers on muestra los nombres de las columnas y .mode column alinea los valores. Los comandos de punto no llevan punto y coma:
.headers on
.mode column
SELECT supplier,sku,title,price_cents,revision,shelf_note
FROM stock ORDER BY supplier,sku;
Hay tres filas de existencias. N / BOLT-1, de North, es Steel bolt, cuesta 120 centavos, tiene la revisión 2 y está en Bin A. W / BOLT-1, de West, es Brass bolt, cuesta 180 centavos, tiene la revisión 1 y está en Drawer 4. Un centavo es la unidad monetaria más pequeña de esta tienda ficticia; 120 significa 1,20. Usar centavos enteros evita el redondeo decimal en este ejercicio. N / WASH-2 también debe seguir disponible.
El par supplier,sku identifica un registro de existencias. El SKU por sí solo no permite distinguir los dos pernos. SELECT * solicita todas las columnas:
SELECT * FROM suppliers ORDER BY code;
Deberías ver N / North Parts y W / West Workshop. El código de proveedor de una entrega debe aparecer en esta tabla.
SQLite comprueba las relaciones de clave foránea por separado en cada conexión. Actívalas en este intérprete. Esta configuración no modifica los datos de existencias:
PRAGMA foreign_keys=ON;
Sal de SQLite con .quit; volverás al intérprete de Linux:
.quit
cat imprime un archivo de texto. Lee el CSV real:
cat deliveries/current.csv
CSV significa valores separados por comas. La primera línea nombra cinco columnas. El archivo contiene precios y revisiones como texto, incluidos 12kits, un proveedor desconocido Z y una fila con el SKU vacío. Son problemas de entrada deliberados, no instrucciones para adivinar una corrección. Los archivos fuente deben permanecer sin cambios. El CSV proporcionado tiene exactamente cinco campos por fila de datos; se admite el uso estándar de comillas en CSV.
Vuelve a abrir la base de datos:
sqlite3 stock.db
La tabla preparada raw_delivery tiene cinco columnas TEXT en ese orden. TEXT conserva exactamente lo recibido, incluidos los números no válidos; importar directamente a stock mezclaría la inspección con las actualizaciones del negocio. .import --csv selecciona el análisis CSV y --skip 1 omite la cabecera:
.import --csv --skip 1 deliveries/current.csv raw_delivery
rowid es el identificador de fila de SQLite para esta tabla intermedia. Resulta útil como número de línea de la entrega, no como identidad del producto. Muestra todas las filas importadas:
.headers on
.mode column
SELECT rowid AS delivery_line,* FROM raw_delivery ORDER BY rowid;
Deberías ver las líneas 1–6 en el orden del archivo. Las líneas 1–3 son los dos pernos y la nueva cinta de reparación. La línea 4 contiene 12kits, la 5 tiene el proveedor Z y la 6 un SKU vacío. AS asigna al rowid mostrado el nombre más claro delivery_line.
Una importación añade filas. Si importaste dos veces por accidente, vacía solo esta tabla intermedia con DELETE FROM raw_delivery; y repite la importación una sola vez. Esta es la recuperación habitual de esta unidad; nunca borres stock ni reinicies toda la VM:
DELETE FROM raw_delivery;
.import --csv --skip 1 deliveries/current.csv raw_delivery
Termina en el intérprete de Linux:
.quit
La entrega cargada en la tabla intermedia es tu primer resultado. Las existencias aún conservan sus tres filas y notas de ubicación originales.
Separar las filas utilizables de los valores no válidos
En este paso, guardarás un script de inspección y usarás sus vistas reales para revisar la entrega. Empieza en Terminal, en /home/labex/project/supplier-desk.
La tienda acepta un proveedor conocido, un SKU no vacío y un nombre que contenga algo más que espacios. Los precios deben contener entre 1 y 6 dígitos ASCII y representar un número positivo. Las revisiones deben contener entre 1 y 3 dígitos ASCII y representar un número positivo. Se permiten los ceros iniciales. Estos límites reducidos son el contrato de entrada; no pretenden validar formatos numéricos arbitrarios.
CREATE VIEW name AS SELECT ... guarda una consulta con un nombre. DROP VIEW IF EXISTS elimina únicamente esa consulta guardada si existe; no elimina la tabla fuente. WHERE conserva las filas cuya condición es verdadera. BETWEEN 1 AND 6 incluye ambos extremos; NOT BETWEEN detecta valores fuera de ellos.
Una expresión CASE selecciona el primer motivo que coincida. WHEN indica una condición y THEN su resultado; si no hay coincidencia, devuelve NULL, que aquí significa que no hay error. IS NULL comprueba esa ausencia. OR combina motivos alternativos para rechazar un valor. NOT IN (SELECT code FROM suppliers) comprueba la pertenencia al conjunto de proveedores. trim elimina los espacios de los extremos y length cuenta los caracteres.
En las comprobaciones numéricas, GLOB '*[^0-9]*' detecta cualquier carácter que no sea un dígito ASCII: * coincide con cualquier secuencia y [^0-9] con un carácter que no sea un dígito. La comprobación de longitud separada rechaza las cadenas vacías. CAST(... AS INTEGER) convierte texto en un entero, pero se usa solo después de las comprobaciones de dígitos y longitud. Convertir sin más es inseguro: un texto como 12kits no debe aceptarse como 12.
Crearás cuatro vistas. delivery_check conserva los valores originales y un motivo. typed_delivery convierte solo las filas válidas. delivery_errors enumera los números de línea rechazados y sus motivos. delivery_ready expone valores aptos para una actualización posterior. El script elimina únicamente estas vistas con nombre para poder ejecutarse de nuevo; nunca borra existencias ni filas fuente.
El siguiente comando de Linux guarda ese SQL en inspect.sql. > reemplaza el archivo de destino. <<'SQL' inicia un here-document literal: pega el bloque completo, incluido el SQL final solo en una línea. No ejecutes este comando cat dentro de SQLite.
cat > inspect.sql <<'SQL'
DROP VIEW IF EXISTS delivery_ready;
DROP VIEW IF EXISTS delivery_errors;
DROP VIEW IF EXISTS typed_delivery;
DROP VIEW IF EXISTS delivery_check;
CREATE VIEW delivery_check AS
SELECT rowid AS delivery_line, *,
CASE
WHEN supplier NOT IN (SELECT code FROM suppliers) OR supplier IS NULL
THEN 'unknown supplier'
WHEN sku IS NULL OR sku = '' THEN 'missing SKU'
WHEN title IS NULL OR trim(title) = '' THEN 'missing title'
WHEN price_cents IS NULL OR length(price_cents) NOT BETWEEN 1 AND 6
OR price_cents GLOB '*[^0-9]*' OR CAST(price_cents AS INTEGER) < 1
THEN 'invalid price'
WHEN revision IS NULL OR length(revision) NOT BETWEEN 1 AND 3
OR revision GLOB '*[^0-9]*' OR CAST(revision AS INTEGER) < 1
THEN 'invalid revision'
END AS reason
FROM raw_delivery;
CREATE VIEW typed_delivery AS
SELECT delivery_line, supplier, sku, title,
CAST(price_cents AS INTEGER) AS price_cents,
CAST(revision AS INTEGER) AS revision
FROM delivery_check WHERE reason IS NULL;
CREATE VIEW delivery_errors AS
SELECT delivery_line, reason FROM delivery_check WHERE reason IS NOT NULL;
CREATE VIEW delivery_ready AS
SELECT supplier,sku,title,price_cents,revision FROM typed_delivery;
SQL
Si la terminal sigue esperando, falta el marcador de cierre: introduce SQL solo en una línea. Si escribiste mal una línea, repite el bloque completo para reemplazar este script. No necesitas un editor ni un reinicio.
Ejecuta un script mediante la redirección de entrada < de Linux. -bail indica a SQLite que se detenga en el primer error en lugar de continuar con las instrucciones posteriores. Si todo funciona, no se espera ninguna salida:
sqlite3 -bail stock.db < inspect.sql
Ante un error común de nombre de archivo o sintaxis, usa ls, vuelve con el cd absoluto del paso 1, corrige inspect.sql usando el bloque completo y ejecútalo de nuevo. Las existencias no se han modificado.
SQLite también acepta una instrucción SQL entre comillas después de la ruta de la base de datos. -header -column selecciona una presentación legible para este único comando. Las comillas mantienen los espacios y los puntos y coma en un solo argumento del intérprete:
sqlite3 -header -column stock.db 'SELECT * FROM delivery_errors ORDER BY delivery_line;'
Resultado esperado:
delivery_line reason
------------- ----------------
4 invalid price
5 unknown supplier
6 missing SKU
El motivo pertenece a una línea de entrega, de modo que se puede rastrear un artículo rechazado hasta la fuente. No se ha corregido ni borrado ningún valor fuente.
sqlite3 -header -column stock.db 'SELECT * FROM delivery_ready ORDER BY supplier,sku;'
Deberías ver tres filas aceptables: el perno de North a 135 centavos/revisión 3, la cinta de reparación a 450/revisión 1 y el perno de West a 190/revisión 2. Las identidades de los dos pernos siguen separadas. typeof informa del tipo real del valor en SQLite:
sqlite3 -header -column stock.db 'SELECT sku,typeof(price_cents),typeof(revision) FROM delivery_ready ORDER BY supplier,sku;'
Ambas columnas de tipo deberían indicar integer. Por último, lee las existencias reales:
sqlite3 -header -column stock.db 'SELECT * FROM stock ORDER BY supplier,sku;'
Todavía conservan sus valores y notas de ubicación originales. Has preparado una inspección de recepción reutilizable; no has aplicado los cambios del proveedor. El siguiente laboratorio guiado independiente comienza con una base de datos nueva y una entrega mayor ya cargada en la tabla intermedia.
Resumen
Usaste filas reales de SQLite para relacionar las identidades de los proveedores, los valores de las entregas y las existencias locales. Interpretaste los registros realmente aceptados y rechazados, conservaste las fuentes originales y guardaste SQL reutilizable para la próxima entrega.



