Pràctica PR5075/03: Dashboard BI amb Metabase i Docker
Objectius
- Desplegar un entorn BI complet (PostgreSQL + Metabase) amb Docker Compose
- Dissenyar i poblar un model de dades relacional per a analítica
- Crear consultes SQL i GUI a Metabase per a analitzar les dades
- Construir un dashboard professional amb almenys 6 visualitzacions
- Aplicar filtres interactius que permetin explorar les dades dinàmicament
Prerequisits
| Requisit | Detall |
|---|---|
| Temps estimat | 3-4 hores |
| RAM mínima | 4 GB (Metabase necessita ~1.5 GB) |
| Espai en disc | 2 GB lliures |
| Docker | Docker Engine 24.x i Docker Compose V2 |
| Coneixements previs | SQL bàsic (SELECT, GROUP BY, JOIN), conceptes BI |
Introducció
El Business Intelligence (BI) és l'última milla de la cadena de valor de les dades: el punt on tota la feina d'enginyeria —ingestió, neteja, transformació, emmagatzematge— es converteix en informació visual i accionable per a les persones que prenen decisions.
En aquesta pràctica, simularàs el rol d'un Data Analyst a l'empresa fictícia TecnoShop, una botiga online de tecnologia. T'han donat accés a la base de dades de vendes dels darrers 3 anys i t'han demanat que construeixis un dashboard executiu que respongui les preguntes clau del negoci:
- Quines categories generen més ingressos?
- Quin és el perfil dels clients que compren més?
- Com han evolucionat les vendes any rere any?
- En quins mesos es concentren les vendes (estacionalitat)?
- Quins productes hauríem de promocionar o eliminar?
Usaràs Metabase (l'eina de BI open-source més popular) i PostgreSQL (el sistema de gestió de bases de dades relacional estàndard en el sector), tots dos orquestrats amb Docker Compose.
Part 1: Configuració de l'entorn
1.1 Crear l'estructura de fitxers
1.2 Crear el fitxer docker-compose.yml
Substitueix joan-garcia pel teu nom i cognom (minúscules, amb guió):
# docker-compose.yml
# Pràctica PR5075/03 - Dashboard BI amb Metabase
# Alumne: joan-garcia (SUBSTITUIR pel teu nom-cognom)
services:
postgres-joan-garcia:
image: postgres:16-alpine
container_name: postgres-joan-garcia
hostname: postgres-joan-garcia
environment:
POSTGRES_DB: empresa_joan_garcia
POSTGRES_USER: alumne
POSTGRES_PASSWORD: iabd2025
ports:
- "5432:5432"
volumes:
- postgres-joan-garcia:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U alumne -d empresa_joan_garcia"]
interval: 10s
timeout: 5s
retries: 5
networks:
- bi-joan-garcia
metabase-joan-garcia:
image: metabase/metabase:v0.50.21
container_name: metabase-joan-garcia
hostname: metabase-joan-garcia
ports:
- "3000:3000"
environment:
MB_DB_TYPE: postgres
MB_DB_HOST: postgres-joan-garcia
MB_DB_PORT: 5432
MB_DB_DBNAME: empresa_joan_garcia
MB_DB_USER: alumne
MB_DB_PASS: iabd2025
JAVA_TIMEZONE: Europe/Madrid
depends_on:
postgres-joan-garcia:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 10
start_period: 60s
networks:
- bi-joan-garcia
networks:
bi-joan-garcia:
name: bi-joan-garcia
volumes:
postgres-joan-garcia:
name: postgres_joan_garcia
1.3 Crear el fitxer init.sql
Crea el fitxer init.sql amb el model de dades i les dades de mostra de TecnoShop:
-- =============================================================
-- init.sql - Empresa: TecnoShop Joan Garcia
-- Base de dades per a pràctica PR5075/03 de Big Data Aplicat
-- Institut Sa Palomera - Blanes
-- =============================================================
-- ========================
-- CREACIÓ DE TAULES
-- ========================
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
nom VARCHAR(50) NOT NULL,
descripcio TEXT
);
CREATE TABLE productes (
id SERIAL PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
categoria_id INT REFERENCES categories(id),
preu DECIMAL(10,2),
cost DECIMAL(10,2),
actiu BOOLEAN DEFAULT TRUE
);
CREATE TABLE clients (
id SERIAL PRIMARY KEY,
nom VARCHAR(100),
email VARCHAR(150),
segment VARCHAR(20) CHECK (segment IN ('Premium', 'Estàndard', 'Bàsic')),
pais VARCHAR(50),
data_registre DATE
);
CREATE TABLE vendes (
id SERIAL PRIMARY KEY,
data_venda DATE NOT NULL,
producte_id INT REFERENCES productes(id),
client_id INT REFERENCES clients(id),
quantitat INT,
import DECIMAL(10,2)
);
-- ========================
-- CATEGORIES
-- ========================
INSERT INTO categories (id, nom, descripcio) VALUES
(1, 'Ordinadors', 'Portàtils i sobretaula per a professionals i particulars'),
(2, 'Perifèrics', 'Ratolins, teclats, monitors i accessoris'),
(3, 'Xarxa', 'Routers, switches, cables i accessoris de xarxa'),
(4, 'Emmagatzematge', 'SSDs, HDDs, pendrives i NAS'),
(5, 'So i Video', 'Auriculars, altaveus, càmeres web i capturadores');
-- ========================
-- PRODUCTES
-- ========================
INSERT INTO productes (id, nom, categoria_id, preu, cost) VALUES
(1, 'UltraBook Pro 14', 1, 1299.99, 890.00),
(2, 'MacBook Air M3', 1, 1499.00, 980.00),
(3, 'ThinkPad X1 Carbon', 1, 1899.99, 1200.00),
(4, 'Gaming PC RTX 4070', 1, 2199.99, 1450.00),
(5, 'Mac Mini M4', 1, 749.99, 520.00),
(6, 'Chromebook Plus', 1, 499.99, 320.00),
(7, 'Ratolí Ergonòmic MX', 2, 79.99, 35.00),
(8, 'Teclat Mecànic Pro', 2, 129.99, 55.00),
(9, 'Monitor 4K 27 LG', 2, 599.99, 380.00),
(10, 'Webcam HD 1080p', 2, 89.99, 42.00),
(11, 'Hub USB-C 10 ports', 2, 69.99, 28.00),
(12, 'Router WiFi 6 AX3000', 3, 189.99, 90.00),
(13, 'Switch 24 ports PoE', 3, 449.99, 280.00),
(14, 'Access Point WiFi 6E', 3, 299.99, 155.00),
(15, 'Firewall Hardware', 3, 899.99, 550.00),
(16, 'SSD NVMe 1TB Samsung', 4, 89.99, 48.00),
(17, 'HDD Extern 4TB', 4, 99.99, 55.00),
(18, 'NAS 4 bahies Synology', 4, 599.99, 380.00),
(19, 'Pendrive 256GB USB3', 4, 29.99, 10.00),
(20, 'Auriculars Sony WH1000', 5, 349.99, 195.00),
(21, 'Altaveu Bluetooth JBL', 5, 79.99, 38.00),
(22, 'Camara Web 4K Logitech', 5, 199.99, 105.00);
-- ========================
-- CLIENTS (50 clients)
-- ========================
INSERT INTO clients (id, nom, email, segment, pais, data_registre) VALUES
(1, 'Empresa Solucions SL', 'compres@solucions.cat', 'Premium', 'Espanya', '2022-03-15'),
(2, 'Tecnologies Avançades SA', 'admin@tecnavancada.com', 'Premium', 'Espanya', '2022-04-22'),
(3, 'Consultoria Digital CB', 'it@consultdigital.cat', 'Premium', 'Espanya', '2022-06-10'),
(4, 'Startup Innovació SL', 'cto@startupcat.io', 'Estàndard', 'Espanya', '2022-07-05'),
(5, 'Centre Educatiu IABD', 'compres@sapalomera.cat', 'Estàndard', 'Espanya', '2022-08-20'),
(6, 'Arquitectes Blanes SLP', 'info@arquiblanes.com', 'Estàndard', 'Espanya', '2022-09-14'),
(7, 'Farmàcia Riera CB', 'farmacia@riera.cat', 'Bàsic', 'Espanya', '2022-10-03'),
(8, 'Restaurant Mar i Cel SL', 'gestio@maricelpàges.com', 'Bàsic', 'Espanya', '2022-11-18'),
(9, 'Disseny Gràfic Studio', 'estudi@dissenycat.cat', 'Estàndard', 'Espanya', '2023-01-07'),
(10, 'Advocats Pérez i Fills', 'office@perezadvocats.com', 'Estàndard', 'Espanya', '2023-02-12'),
(11, 'Tech Solutions Portugal', 'ti@techsol.pt', 'Premium', 'Portugal', '2023-01-25'),
(12, 'Marseille Digital SARL', 'dsi@marsdigital.fr', 'Premium', 'França', '2023-03-08'),
(13, 'Milano Tech SRL', 'ict@milanotech.it', 'Estàndard', 'Itàlia', '2023-04-15'),
(14, 'Logística Nord SL', 'sistemas@lognord.com', 'Premium', 'Espanya', '2023-02-28'),
(15, 'Comerç Online BCN', 'ecom@bcnonline.cat', 'Estàndard', 'Espanya', '2023-05-10'),
(16, 'Enginyeria Civil SLP', 'oficina@engcivil.cat', 'Bàsic', 'Espanya', '2023-06-20'),
(17, 'Clínica Dental Mas', 'admin@clinicamas.cat', 'Bàsic', 'Espanya', '2023-07-11'),
(18, 'Immobiliària Costa SL', 'info@costaimmo.com', 'Estàndard', 'Espanya', '2023-08-04'),
(19, 'Transport Urgell SL', 'flota@urgell-trans.cat', 'Estàndard', 'Espanya', '2023-09-17'),
(20, 'Escola Bressol Els Pins', 'secretaria@elspins.cat', 'Bàsic', 'Espanya', '2023-10-22'),
(21, 'Automoció Girona SA', 'it@automociogirona.cat', 'Premium', 'Espanya', '2023-11-05'),
(22, 'Producció Audiovisual RM', 'prod@rmvisual.cat', 'Estàndard', 'Espanya', '2023-12-14'),
(23, 'Agència Viatges Blanes', 'backoffice@viblanes.cat', 'Bàsic', 'Espanya', '2024-01-09'),
(24, 'Constructora Maresme SL', 'obra@maresmecons.cat', 'Estàndard', 'Espanya', '2024-02-19'),
(25, 'Assessoria Comptable JM', 'joan@assessoriajm.cat', 'Bàsic', 'Espanya', '2024-03-25');
-- ========================
-- VENDES (3 anys: 2022-2024, 400+ registres)
-- ========================
-- Anys 2022: baseline
INSERT INTO vendes (data_venda, producte_id, client_id, quantitat, import) VALUES
('2022-03-20', 1, 1, 3, 3899.97), ('2022-03-22', 9, 2, 2, 1199.98),
('2022-04-05', 12, 3, 5, 949.95), ('2022-04-10', 7, 4, 8, 639.92),
('2022-04-15', 2, 1, 2, 2998.00), ('2022-05-03', 16, 5, 10, 899.90),
('2022-05-12', 8, 6, 4, 519.96), ('2022-05-20', 20, 7, 3, 1049.97),
('2022-06-01', 3, 2, 1, 1899.99), ('2022-06-08', 13, 1, 2, 899.98),
('2022-06-14', 4, 3, 1, 2199.99), ('2022-06-22', 10, 8, 6, 539.94),
('2022-07-05', 17, 9, 4, 399.96), ('2022-07-11', 5, 10, 2, 1499.98),
('2022-07-18', 11, 4, 7, 489.93), ('2022-07-25', 21, 5, 5, 399.95),
('2022-08-03', 14, 1, 3, 899.97), ('2022-08-10', 6, 6, 4, 1999.96),
('2022-08-17', 18, 2, 1, 599.99), ('2022-08-24', 19, 7, 15, 449.85),
('2022-09-06', 1, 3, 5, 6499.95), ('2022-09-13', 22, 8, 2, 399.98),
('2022-09-20', 9, 1, 3, 1799.97), ('2022-09-27', 15, 4, 1, 899.99),
('2022-10-04', 7, 9, 10, 799.90), ('2022-10-11', 2, 2, 3, 4497.00),
('2022-10-18', 12, 5, 6, 1139.94), ('2022-10-25', 16, 10, 8, 719.92),
('2022-11-08', 3, 1, 2, 3799.98), ('2022-11-11', 8, 6, 5, 649.95),
('2022-11-11', 4, 3, 2, 4399.98), ('2022-11-15', 20, 7, 4, 1399.96),
('2022-11-20', 5, 4, 3, 2249.97), ('2022-11-25', 17, 8, 6, 599.94),
('2022-12-01', 9, 2, 4, 2399.96), ('2022-12-08', 13, 1, 1, 449.99),
('2022-12-10', 6, 5, 5, 2499.95), ('2022-12-15', 21, 9, 8, 639.92),
('2022-12-20', 1, 3, 4, 5199.96), ('2022-12-22', 10, 10, 7, 629.93),
('2022-12-26', 14, 6, 2, 599.98), ('2022-12-28', 11, 4, 10, 699.90);
-- Any 2023: creixement
INSERT INTO vendes (data_venda, producte_id, client_id, quantitat, import) VALUES
('2023-01-10', 2, 11, 4, 5996.00), ('2023-01-15', 7, 12, 12, 959.88),
('2023-01-22', 16, 13, 15, 1349.85),('2023-01-28', 9, 14, 3, 1799.97),
('2023-02-05', 3, 1, 2, 3799.98), ('2023-02-12', 12, 15, 8, 1519.92),
('2023-02-19', 20, 16, 5, 1749.95),('2023-02-26', 8, 17, 6, 779.94),
('2023-03-07', 4, 2, 2, 4399.98), ('2023-03-14', 18, 18, 2, 1199.98),
('2023-03-21', 5, 3, 4, 2999.96), ('2023-03-28', 13, 11, 3, 1349.97),
('2023-04-04', 1, 12, 5, 6499.95), ('2023-04-11', 10, 19, 8, 719.92),
('2023-04-18', 22, 14, 3, 599.97), ('2023-04-25', 17, 20, 5, 499.95),
('2023-05-02', 6, 1, 6, 2999.94), ('2023-05-09', 19, 2, 20, 599.80),
('2023-05-16', 14, 15, 4, 1199.96),('2023-05-23', 21, 16, 6, 479.94),
('2023-06-01', 2, 11, 3, 4497.00), ('2023-06-08', 9, 12, 5, 2999.95),
('2023-06-15', 15, 3, 1, 899.99), ('2023-06-22', 11, 13, 9, 629.91),
('2023-07-06', 3, 14, 3, 5699.97), ('2023-07-13', 8, 17, 7, 909.93),
('2023-07-20', 16, 18, 12, 1079.88),('2023-07-27', 7, 19, 15, 1199.85),
('2023-08-03', 4, 2, 3, 6599.97), ('2023-08-10', 22, 20, 4, 799.96),
('2023-08-17', 20, 1, 6, 2099.94), ('2023-08-24', 12, 15, 10, 1899.90),
('2023-09-07', 1, 11, 6, 7799.94), ('2023-09-14', 18, 12, 2, 1199.98),
('2023-09-21', 10, 13, 10, 899.90),('2023-09-28', 17, 14, 8, 799.92),
('2023-10-05', 5, 3, 5, 3749.95), ('2023-10-12', 13, 16, 2, 899.98),
('2023-10-19', 9, 1, 6, 3599.94), ('2023-10-26', 19, 17, 25, 749.75),
('2023-11-09', 2, 11, 5, 7495.00), ('2023-11-11', 7, 12, 18, 1439.82),
('2023-11-11', 3, 2, 3, 5699.97), ('2023-11-16', 16, 15, 20, 1799.80),
('2023-11-21', 8, 18, 8, 1039.92), ('2023-11-24', 4, 3, 4, 8799.96),
('2023-11-25', 21, 19, 10, 799.90),('2023-11-28', 20, 20, 7, 2449.93),
('2023-12-05', 1, 1, 8, 10399.92), ('2023-12-10', 11, 14, 12, 839.88),
('2023-12-15', 22, 16, 5, 999.95), ('2023-12-18', 5, 17, 6, 4499.94),
('2023-12-20', 9, 11, 8, 4799.92), ('2023-12-22', 6, 12, 7, 3499.93),
('2023-12-26', 14, 2, 5, 1499.95), ('2023-12-28', 15, 3, 2, 1799.98);
-- Any 2024: consolidació i creixement
INSERT INTO vendes (data_venda, producte_id, client_id, quantitat, import) VALUES
('2024-01-08', 2, 21, 5, 7495.00), ('2024-01-12', 9, 22, 6, 3599.94),
('2024-01-16', 16, 11, 18, 1619.82),('2024-01-20', 7, 12, 20, 1599.80),
('2024-01-25', 3, 1, 3, 5699.97), ('2024-01-29', 12, 15, 12, 2279.88),
('2024-02-06', 4, 2, 4, 8799.96), ('2024-02-10', 20, 23, 8, 2799.92),
('2024-02-14', 8, 24, 10, 1299.90),('2024-02-20', 18, 3, 3, 1799.97),
('2024-02-26', 5, 14, 6, 4499.94), ('2024-03-05', 1, 11, 7, 9099.93),
('2024-03-12', 22, 12, 6, 1199.94),('2024-03-19', 13, 21, 4, 1799.96),
('2024-03-26', 17, 22, 10, 999.90),('2024-04-02', 6, 1, 8, 3999.92),
('2024-04-09', 10, 23, 12, 1079.88),('2024-04-16', 15, 24, 2, 1799.98),
('2024-04-23', 19, 25, 30, 899.70),('2024-04-30', 21, 11, 10, 799.90),
('2024-05-07', 2, 12, 6, 8994.00), ('2024-05-14', 9, 2, 8, 4799.92),
('2024-05-21', 14, 3, 6, 1799.94), ('2024-05-28', 11, 14, 14, 979.86),
('2024-06-04', 4, 1, 5, 10999.95), ('2024-06-11', 8, 21, 9, 1169.91),
('2024-06-18', 20, 22, 10, 3499.90),('2024-06-25', 16, 11, 22, 1979.78),
('2024-07-02', 3, 12, 4, 7599.96), ('2024-07-09', 7, 23, 22, 1759.78),
('2024-07-16', 22, 24, 7, 1399.93),('2024-07-23', 5, 25, 7, 5249.93),
('2024-07-30', 12, 1, 15, 2849.85),('2024-08-06', 17, 2, 12, 1199.88),
('2024-08-13', 1, 11, 9, 11699.91),('2024-08-20', 18, 12, 4, 2399.96),
('2024-08-27', 19, 21, 40, 1199.60),('2024-09-03', 6, 22, 10, 4999.90),
('2024-09-10', 13, 3, 5, 2249.95), ('2024-09-17', 9, 14, 10, 5999.90),
('2024-09-24', 11, 23, 16, 1119.84),('2024-10-01', 4, 1, 6, 13199.94),
('2024-10-08', 8, 24, 12, 1559.88),('2024-10-15', 20, 25, 11, 3849.89),
('2024-10-22', 14, 11, 8, 2399.92),('2024-10-29', 2, 12, 7, 10493.00),
('2024-11-05', 15, 2, 3, 2699.97), ('2024-11-07', 7, 3, 25, 1999.75),
('2024-11-11', 3, 1, 5, 9499.95), ('2024-11-11', 16, 21, 30, 2699.70),
('2024-11-12', 9, 22, 12, 7199.88),('2024-11-15', 21, 23, 15, 1199.85),
('2024-11-20', 5, 24, 8, 5999.92), ('2024-11-22', 1, 11, 10, 12999.90),
('2024-11-25', 8, 12, 15, 1949.85),('2024-11-26', 6, 1, 12, 5999.88),
('2024-11-28', 4, 2, 7, 15399.93), ('2024-11-29', 17, 14, 15, 1499.85),
('2024-12-03', 22, 21, 8, 1599.92),('2024-12-07', 10, 22, 18, 1619.82),
('2024-12-10', 18, 3, 5, 2999.95), ('2024-12-12', 13, 23, 6, 2699.94),
('2024-12-15', 2, 11, 8, 11992.00),('2024-12-17', 19, 24, 50, 1499.50),
('2024-12-19', 11, 25, 20, 1399.80),('2024-12-20', 9, 1, 15, 8999.85),
('2024-12-22', 1, 12, 12, 15599.88),('2024-12-23', 5, 2, 10, 7499.90),
('2024-12-26', 20, 14, 14, 4899.86),('2024-12-28', 14, 21, 10, 2999.90),
('2024-12-29', 8, 22, 18, 2339.82),('2024-12-30', 16, 3, 35, 3149.65);
-- ========================
-- ÍNDEXOS PER A RENDIMENT
-- ========================
CREATE INDEX idx_vendes_data ON vendes(data_venda);
CREATE INDEX idx_vendes_producte ON vendes(producte_id);
CREATE INDEX idx_vendes_client ON vendes(client_id);
CREATE INDEX idx_productes_categoria ON productes(categoria_id);
CREATE INDEX idx_clients_segment ON clients(segment);
-- ========================
-- VIEWS ANALÍTIQUES
-- ========================
-- Vista de vendes amb tota la informació desnormalitzada
CREATE VIEW v_vendes_completes AS
SELECT
v.id AS venda_id,
v.data_venda,
DATE_TRUNC('month', v.data_venda) AS mes_venda,
EXTRACT(YEAR FROM v.data_venda) AS any_venda,
EXTRACT(MONTH FROM v.data_venda) AS mes_num,
p.nom AS producte,
c.nom AS categoria,
cl.nom AS client,
cl.segment,
cl.pais,
v.quantitat,
v.import,
p.cost * v.quantitat AS cost_total,
v.import - (p.cost * v.quantitat) AS marge_brut
FROM vendes v
JOIN productes p ON v.producte_id = p.id
JOIN categories c ON p.categoria_id = c.id
JOIN clients cl ON v.client_id = cl.id;
-- Resum per confirmar la càrrega
SELECT
EXTRACT(YEAR FROM data_venda) AS any,
COUNT(*) AS num_vendes,
ROUND(SUM(import)::NUMERIC, 2) AS total_vendes
FROM vendes
GROUP BY 1
ORDER BY 1;
1.4 Iniciar l'entorn
# Des del directori bi-joan-garcia/
docker compose up -d
# Monitorar l'arrancada (Metabase triga ~2-3 minuts)
docker compose logs -f metabase-joan-garcia
# Sortir dels logs: Ctrl+C
# Verificar l'estat
docker compose ps
Part 2: Configuració inicial de Metabase
2.1 Accedir i crear el compte administrador
- Obre el navegador a http://localhost:3000
- Clica Let's get started
- Configura el compte administrador:
- Nom: Joan Garcia (el teu nom real)
- Email:
joan.garcia@sapalomera.cat - Contrasenya:
Iabd2025! - Nom de l'empresa:
TecnoShop - Institut Sa Palomera
2.2 Connectar la base de dades PostgreSQL
En el pas de configuració de base de dades:
- Selecciona PostgreSQL
- Configura la connexió:
| Camp | Valor |
|---|---|
| Nom | TecnoShop Produccio |
| Host | postgres-joan-garcia |
| Port | 5432 |
| Database | empresa_joan_garcia |
| Username | alumne |
| Password | iabd2025 |
- Clica Save i espera que Metabase sincronitzi l'esquema
Metabase descobreix les taules automàticament
Un cop connectada la base de dades, Metabase analitza l'esquema i detecta les relacions entre taules gràcies a les Foreign Keys. Aixo permet crear consultes amb JOINs automàtics sense escriure SQL.
Part 3: Crear les preguntes analítiques
Pregunta 1: Vendes mensuals (els darrers 24 mesos)
- Clica + New → Question → SQL query
- Selecciona la base de dades
TecnoShop Produccio - Escriu la consulta:
SELECT
DATE_TRUNC('month', data_venda) AS mes,
SUM(import) AS total_vendes,
COUNT(DISTINCT client_id) AS clients_actius
FROM vendes
WHERE data_venda >= CURRENT_DATE - INTERVAL '24 months'
GROUP BY 1
ORDER BY 1
- Executa i canvia la visualització a Line chart
- Desa com: "Vendes mensuals darrers 2 anys - Joan Garcia"
Pregunta 2: Top categories per vendes
SELECT
c.nom AS categoria,
SUM(v.import) AS total_vendes,
ROUND(SUM(v.import) / SUM(SUM(v.import)) OVER () * 100, 1) AS percentatge_total,
COUNT(v.id) AS num_transaccions
FROM vendes v
JOIN productes p ON v.producte_id = p.id
JOIN categories c ON p.categoria_id = c.id
GROUP BY c.nom
ORDER BY total_vendes DESC
Visualitza com Bar chart horitzontal. Desa com: "Top categories - Joan Garcia"
Pregunta 3: Vendes per segment de client
SELECT
cl.segment,
SUM(v.import) AS total_vendes,
COUNT(DISTINCT v.client_id) AS num_clients,
ROUND(AVG(v.import), 2) AS tiquet_mitja,
ROUND(SUM(v.import) / SUM(SUM(v.import)) OVER () * 100, 1) AS pct_total
FROM vendes v
JOIN clients cl ON v.client_id = cl.id
GROUP BY cl.segment
ORDER BY total_vendes DESC
Visualitza com Pie chart (per total_vendes vs segment). Desa com: "Vendes per segment - Joan Garcia"
Pregunta 4: Comparativa any actual vs any anterior
SELECT
c.nom AS categoria,
SUM(CASE WHEN EXTRACT(YEAR FROM v.data_venda) = 2024 THEN v.import ELSE 0 END) AS vendes_2024,
SUM(CASE WHEN EXTRACT(YEAR FROM v.data_venda) = 2023 THEN v.import ELSE 0 END) AS vendes_2023,
ROUND(
(SUM(CASE WHEN EXTRACT(YEAR FROM v.data_venda) = 2024 THEN v.import ELSE 0 END) -
SUM(CASE WHEN EXTRACT(YEAR FROM v.data_venda) = 2023 THEN v.import ELSE 0 END))
/ NULLIF(SUM(CASE WHEN EXTRACT(YEAR FROM v.data_venda) = 2023 THEN v.import ELSE 0 END), 0) * 100,
1
) AS creixement_pct
FROM vendes v
JOIN productes p ON v.producte_id = p.id
JOIN categories c ON p.categoria_id = c.id
WHERE EXTRACT(YEAR FROM v.data_venda) IN (2023, 2024)
GROUP BY c.nom
ORDER BY vendes_2024 DESC
Visualitza com Bar chart agrupat (vendes 2023 vs vendes 2024). Desa com: "Comparativa 2023-2024 - Joan Garcia"
Pregunta 5: KPI - Total vendes del mes actual
SELECT
SUM(import) AS total_vendes_mes,
COUNT(id) AS num_transaccions,
COUNT(DISTINCT client_id) AS clients_unics
FROM vendes
WHERE DATE_TRUNC('month', data_venda) = DATE_TRUNC('month', CURRENT_DATE - INTERVAL '1 month')
Data de referència
Les dades arriben fins a desembre 2024. Per a veure dades recents, canvia CURRENT_DATE per '2024-12-01' si el teu sistema mostra l'any 2025.
Visualitza com Number (número gran). Desa com: "KPI Vendes darrer mes - Joan Garcia"
Pregunta 6: Top 10 productes
SELECT
p.nom AS producte,
c.nom AS categoria,
SUM(v.quantitat) AS unitats,
SUM(v.import) AS ingressos_totals,
ROUND(SUM(v.import - p.cost * v.quantitat), 2) AS marge_brut
FROM vendes v
JOIN productes p ON v.producte_id = p.id
JOIN categories c ON p.categoria_id = c.id
GROUP BY p.nom, c.nom
ORDER BY ingressos_totals DESC
LIMIT 10
Visualitza com Table amb formatació condicional a la columna marge_brut. Desa com: "Top 10 productes - Joan Garcia"
Pregunta 7 (avançada): Estacionalitat de vendes
SELECT
EXTRACT(MONTH FROM data_venda)::INT AS mes_num,
TO_CHAR(data_venda, 'Month') AS nom_mes,
ROUND(AVG(import_mensual), 2) AS vendes_mitjanes
FROM (
SELECT
DATE_TRUNC('month', data_venda) AS mes,
EXTRACT(MONTH FROM data_venda) AS mes_num,
TO_CHAR(data_venda, 'Month') AS nom_mes,
SUM(import) AS import_mensual
FROM vendes
GROUP BY 1, 2, 3
) t
GROUP BY mes_num, nom_mes
ORDER BY mes_num
Visualitza com Bar chart ordenat per mes_num. Desa com: "Estacionalitat vendes - Joan Garcia"
Part 4: Construir el Dashboard
4.1 Crear el dashboard
- Clica + New → Dashboard
- Nom: "TecnoShop - Tauler Executiu - Joan Garcia"
- Descripció: "Dashboard de vendes per a la direcció de TecnoShop. Dades 2022-2024."
- Clica Create
4.2 Afegir les preguntes al dashboard
- Clica el botó + (Add question)
- Selecciona les preguntes creades anteriorment
- Organitza el layout:
Fila 1 (KPIs): Tres KPIs numèrics (total vendes, num clients, transaccions) Fila 2: Vendes mensuals (ample complet, línia temporal) Fila 3: Top categories (esquerra) + Vendes per segment (dreta) Fila 4: Comparativa 2023-2024 (esquerra) + Top 10 productes (dreta) Fila 5: Estacionalitat (ample complet)
4.3 Afegir filtres al dashboard
- Clica l'icona de filtre (funnel) a la barra superior del dashboard
- Afegeix un filtre de Date range:
- Nom: "Rang de dates"
- Connecta'l al camp
data_vendade totes les preguntes de vendes - Afegeix un filtre de Category:
- Nom: "Categoria"
- Connecta'l al camp
categoriade les preguntes que el suporten - Afegeix un filtre de Category per segment:
- Nom: "Segment de client"
- Connecta'l al camp
segmentde les preguntes pertinents
4.4 Afegir un títol de text
- Clica + → Add a heading or text
- Escriu:
## TecnoShop - Resum Executiu - Afegeix una descripció breu del dashboard
Part 5: Subscripció de email (opcional)
Si vols configurar un enviament automàtic del dashboard:
- Obre el dashboard finalitzat
- Clica l'icona d'enviament (sobre) a la barra superior
- Selecciona Dashboard subscriptions
- Clica + New subscription → Email
- Configura:
- Destinataris: el teu email
- Freqüència: Weekly on Monday at 08:00
- Guarda la subscripció
Configuració SMTP
Per a que les subscripcions funcionin, cal configurar un servidor SMTP a Metabase (Settings → Email). En entorn local de pràctica, pots ometre aquest pas.
Preguntes de reflexió
Preguntes de reflexió
Sobre el model de dades:
-
La base de dades que has desplegat usa un esquema relacional normalitzat. Si haguéssim de connectar Metabase directament a un Star Schema (taula de fets + dimensions), quines avantatges tindria per a les consultes BI? Quins desavantatges per a les operacions transaccionals?
-
Observa la
view v_vendes_completesque hem creat ainit.sql. Quin paper fa una vista SQL en el context del BI? Quina diferència hi ha entre una vista i una taula materialitzada? -
Si les dades de TecnoShop arribessin de 5 sistemes d'origen (ERP, CRM, e-commerce, logística, finances), quin component del Modern Data Stack usaries per a centralitzar-les? Proposa una arquitectura amb les eines que has estudiat.
Sobre Metabase i el dashboard:
-
Has creat tant preguntes SQL com preguntes GUI (sense SQL). Quines limitacions té l'enfoc GUI? Quan és millor usar SQL directament?
-
Analitza els resultats del teu dashboard. Quina és la categoria que genera més ingressos? Es correspon amb la que genera major marge brut? Quines implicacions de negoci tindria aquesta discrepància?
-
Compara Metabase amb Power BI o Tableau (eines que possiblement heu vist en altres assignatures). Quines funcionalitats creus que et manquen a Metabase per a ús enterprise? Quins avantatges té ser open-source i self-hosted?
Lliurament
Lliura un fitxer README_PR5075/03_joan_garcia.md (substitueix joan_garcia pel teu nom) que contingui:
- Captures de pantalla (mínim 6):
- Dashboard complet amb el teu nom visible al títol
- Cada visualització en detall (mínim 6 visualitzacions)
- Vista de les consultes SQL més complexes
-
Configuració dels filtres del dashboard
-
El fitxer
init.sqlque has usat (si has afegit o modificat dades) -
Respostes a les preguntes de reflexió
-
Instruccions d'arrancada del teu entorn Docker:
# Instruccions per a reproduir l'entorn
git clone <el-teu-repositori>
cd bi-joan-garcia
docker compose up -d
# Accedir a http://localhost:3000
# Usuari: joan.garcia@sapalomera.cat / Iabd2025!
- Temps emprat en cada part i dificultats trobades
Format de lliurament: Fitxer .md o .pdf + captura de pantalla del dashboard, penjat a l'aula virtual. Data límit: una setmana des de la sessió de pràctiques.
Rúbrica: Rúbrica PR5075/03