-- Database struktur til månedlige Bygma prisbøger -- Dette skema håndterer løbende prisimport fra Bygma's månedlige prislister -- Hovedtabel for Bygma produkter (master data) CREATE TABLE IF NOT EXISTS bygma_products ( id INT AUTO_INCREMENT PRIMARY KEY, -- Produkt identifikation product_code VARCHAR(255) NOT NULL UNIQUE, -- VareNr fra CSV product_group VARCHAR(100) NOT NULL, -- Varegrp fra CSV product_name TEXT NOT NULL, -- Tekst fra CSV unit VARCHAR(50) NOT NULL, -- Enhed fra CSV -- Tekniske felter db_number VARCHAR(100), -- DB-nr fra CSV ean_number VARCHAR(100), -- EAN-nr fra CSV standard_field VARCHAR(100), -- Std fra CSV -- Metadata first_seen DATE NOT NULL, last_seen DATE NOT NULL, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- Indices for performance INDEX idx_product_code (product_code), INDEX idx_product_group (product_group), INDEX idx_product_name (product_name(100)), INDEX idx_active (is_active), INDEX idx_last_seen (last_seen) ); -- Varegrupper/kategorier fra Bygma CREATE TABLE IF NOT EXISTS bygma_product_groups ( id INT AUTO_INCREMENT PRIMARY KEY, group_code VARCHAR(100) NOT NULL UNIQUE, -- Varegrp fra CSV group_name VARCHAR(255), -- Kan tilføjes manuelt eller mapping parent_group VARCHAR(100), -- For hierarkisk struktur description TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_group_code (group_code), INDEX idx_group_name (group_name) ); -- Prishistorik fra månedlige imports CREATE TABLE IF NOT EXISTS bygma_price_history ( id INT AUTO_INCREMENT PRIMARY KEY, product_id INT NOT NULL, -- Priser fra CSV gross_price DECIMAL(15,2) NOT NULL, -- BruttoPris fra CSV net_price DECIMAL(15,2) NOT NULL, -- Nettopris fra CSV (vores indkøbspris) update_flag TINYINT NOT NULL DEFAULT 1, -- Opdat fra CSV -- Import metadata import_date DATE NOT NULL, -- Dato for denne import import_file VARCHAR(255) NOT NULL, -- Filnavn på importeret CSV import_batch_id VARCHAR(100) NOT NULL, -- Unik ID for denne import batch file_hash VARCHAR(64), -- SHA256 hash af CSV fil for duplikat check -- Validering is_current BOOLEAN DEFAULT TRUE, -- Er dette den aktuelle pris? price_change_pct DECIMAL(8,4), -- Procentvis ændring fra forrige pris created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (product_id) REFERENCES bygma_products(id) ON DELETE CASCADE, -- Indices for performance INDEX idx_product_date (product_id, import_date), INDEX idx_import_batch (import_batch_id), INDEX idx_import_date (import_date), INDEX idx_current (is_current), INDEX idx_file_hash (file_hash), -- Unik constraint: kun én pris per produkt per import UNIQUE KEY unique_product_import (product_id, import_batch_id) ); -- Log over imports for sporing CREATE TABLE IF NOT EXISTS bygma_import_log ( id INT AUTO_INCREMENT PRIMARY KEY, -- Import detaljer import_batch_id VARCHAR(100) NOT NULL UNIQUE, filename VARCHAR(255) NOT NULL, filepath VARCHAR(500) NOT NULL, file_size BIGINT NOT NULL, file_hash VARCHAR(64) NOT NULL, -- Import statistik total_rows INT NOT NULL DEFAULT 0, processed_rows INT NOT NULL DEFAULT 0, successful_rows INT NOT NULL DEFAULT 0, failed_rows INT NOT NULL DEFAULT 0, new_products INT NOT NULL DEFAULT 0, updated_prices INT NOT NULL DEFAULT 0, -- Fejl og advarsler error_summary JSON, -- Samling af fejl der opstod warnings JSON, -- Advarsler (fx store prisændringer) -- Import tider started_at TIMESTAMP NOT NULL, completed_at TIMESTAMP, duration_seconds INT, -- Status status ENUM('running', 'completed', 'failed', 'cancelled') DEFAULT 'running', imported_by VARCHAR(100), -- Hvem startede importen INDEX idx_batch_id (import_batch_id), INDEX idx_filename (filename), INDEX idx_status (status), INDEX idx_started_at (started_at), INDEX idx_file_hash (file_hash) ); -- Aktuelle priser view for nem adgang CREATE OR REPLACE VIEW bygma_current_prices AS SELECT p.id as product_id, p.product_code, p.product_group, p.product_name, p.unit, p.db_number, p.ean_number, ph.gross_price, ph.net_price, ph.import_date, ph.import_file, p.is_active as product_active FROM bygma_products p JOIN bygma_price_history ph ON p.id = ph.product_id WHERE ph.is_current = TRUE AND p.is_active = TRUE; -- Integration med eksisterende materials system -- Denne tabel mapper Bygma produkter til vores materials tabel CREATE TABLE IF NOT EXISTS bygma_materials_mapping ( id INT AUTO_INCREMENT PRIMARY KEY, -- Links bygma_product_id INT NOT NULL, material_id INT, -- Kan være NULL hvis ikke mapped endnu -- Mapping detaljer mapping_type ENUM('automatic', 'manual', 'verified') DEFAULT 'automatic', mapping_confidence DECIMAL(3,2), -- 0.00-1.00 confidence score mapping_notes TEXT, -- Auto-sync indstillinger auto_update_price BOOLEAN DEFAULT TRUE, -- Skal priser auto-opdateres i materials? price_markup_pct DECIMAL(8,4) DEFAULT 0, -- Markup på Bygma priser created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, mapped_by VARCHAR(100), FOREIGN KEY (bygma_product_id) REFERENCES bygma_products(id) ON DELETE CASCADE, INDEX idx_bygma_product (bygma_product_id), INDEX idx_material (material_id), INDEX idx_mapping_type (mapping_type), INDEX idx_auto_update (auto_update_price), -- Sikr kun én mapping per Bygma produkt UNIQUE KEY unique_bygma_mapping (bygma_product_id) ); -- Triggers til at opdatere timestamps og vedligeholde data integritet -- Trigger: Opdater last_seen når der kommer ny pris DELIMITER // CREATE TRIGGER tr_bygma_products_update_last_seen AFTER INSERT ON bygma_price_history FOR EACH ROW BEGIN UPDATE bygma_products SET last_seen = NEW.import_date, updated_at = CURRENT_TIMESTAMP WHERE id = NEW.product_id; END// -- Trigger: Deaktiver gamle priser når nye kommer CREATE TRIGGER tr_bygma_price_history_deactivate_old AFTER INSERT ON bygma_price_history FOR EACH ROW BEGIN -- Deaktiver alle andre priser for dette produkt UPDATE bygma_price_history SET is_current = FALSE WHERE product_id = NEW.product_id AND id != NEW.id; END// -- Trigger: Beregn prisændring procentvis CREATE TRIGGER tr_bygma_price_history_calculate_change BEFORE INSERT ON bygma_price_history FOR EACH ROW BEGIN DECLARE prev_price DECIMAL(15,2); -- Find forrige pris SELECT net_price INTO prev_price FROM bygma_price_history WHERE product_id = NEW.product_id AND is_current = TRUE LIMIT 1; -- Beregn ændring hvis der er en forrige pris IF prev_price IS NOT NULL AND prev_price > 0 THEN SET NEW.price_change_pct = ((NEW.net_price - prev_price) / prev_price) * 100; END IF; END// DELIMITER ; -- Indsæt Bygma som leverandør hvis ikke allerede eksisterer INSERT IGNORE INTO bygma_product_groups (group_code, group_name) VALUES ('1000', 'Træ og byggeplader'), ('2000', 'Tagmaterialer'), ('3000', 'Isolering'), ('4000', 'Vinduer og døre'), ('5000', 'Beslag og skruer'), ('6000', 'Maling og behandling'), ('7000', 'VVS og el'), ('8000', 'Værktøj'), ('9000', 'Øvrige materialer'); -- Eksempel på indeks optimering for store datasets -- Partition på import_date hvis vi får mange måneders data -- ALTER TABLE bygma_price_history -- PARTITION BY RANGE (YEAR(import_date) * 100 + MONTH(import_date)) -- (PARTITION p202501 VALUES LESS THAN (202502), -- PARTITION p202502 VALUES LESS THAN (202503), -- PARTITION p_future VALUES LESS THAN MAXVALUE); -- Grants til applikation bruger (tilpas brugernavne efter behov) -- GRANT SELECT, INSERT, UPDATE ON tilbudgivern.bygma_* TO 'tilbudgivern_user'@'localhost'; -- GRANT SELECT ON tilbudgivern.bygma_current_prices TO 'tilbudgivern_user'@'localhost';