-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBuildify.sql
More file actions
555 lines (468 loc) · 24.8 KB
/
Copy pathBuildify.sql
File metadata and controls
555 lines (468 loc) · 24.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
DROP DATABASE IF EXISTS Buildify;
CREATE DATABASE Buildify
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
USE Buildify;
-- TABELLE PRINCIPALI (Cliente, Prodotto, Carrello, Ordine, Build)
CREATE TABLE Cliente (
ClienteID INT PRIMARY KEY AUTO_INCREMENT,
Nome VARCHAR(50) NOT NULL,
Cognome VARCHAR(50) NOT NULL,
Email VARCHAR(100) UNIQUE NOT NULL, -- Controllo a livello applicativo (JAVA)
Telefono VARCHAR(20),
PasswordHash VARCHAR(255) NOT NULL,
Indirizzo VARCHAR(255),
CAP CHAR(5)
);
CREATE TABLE Prodotto (
ProdottoID INT PRIMARY KEY AUTO_INCREMENT,
Nome VARCHAR(100) NOT NULL,
Descrizione VARCHAR(255),
Prezzo DECIMAL(10, 2) NOT NULL,
Marca VARCHAR(100) NOT NULL,
Quantita INT DEFAULT 0,
Sconto DECIMAL(5, 2) DEFAULT 0,
ImmaginePath VARCHAR(255),
CategoriaProdotto ENUM('Hardware', 'Periferica') NOT NULL
);
CREATE TABLE Ordine (
OrdineID INT PRIMARY KEY AUTO_INCREMENT,
DataOrdine DATETIME NOT NULL,
Totale DECIMAL(10,2) NOT NULL,
Stato ENUM('Elaborazione', 'Spedito', 'Consegnato', 'Annullato') NOT NULL,
ClienteID INT NOT NULL,
IndirizzoSpedizione VARCHAR(255) NOT NULL,
CAPSpedizione CHAR(5) NOT NULL,
FOREIGN KEY fk_ordine_cliente (ClienteID) REFERENCES Cliente(ClienteID)
);
-- SPECIALIZZAZIONI
-- Hardware (da specializzare)
CREATE TABLE Hardware (
HardwareID INT PRIMARY KEY,
CategoriaHardware ENUM('CPU', 'GPU', 'RAM', 'PSU', 'SchedaMadre', 'CasePC', 'Archiviazione') NOT NULL,
FOREIGN KEY fk_hardware_prodotto (HardwareID) REFERENCES Prodotto(ProdottoID) ON DELETE CASCADE
);
-- Periferica (da specializzare)
CREATE TABLE Periferica (
PerifericaID INT PRIMARY KEY,
CategoriaPeriferica ENUM('Mouse', 'Tastiera', 'Monitor', 'Cuffie') NOT NULL,
FOREIGN KEY fk_periferica_prodotto (PerifericaID) REFERENCES Prodotto(ProdottoID) ON DELETE CASCADE
);
-- Categorie Hardware
CREATE TABLE CPU (
CpuID INT PRIMARY KEY,
Chipset VARCHAR(50),
FrequenzaGHz FLOAT,
Core INT,
Socket VARCHAR(20),
Cache INT,
FOREIGN KEY fk_cpu_hardware (CpuID) REFERENCES Hardware(HardwareID) ON DELETE CASCADE
);
CREATE TABLE GPU (
GpuID INT PRIMARY KEY,
VramGB INT,
NumeroCore INT,
FOREIGN KEY fk_gpu_hardware (GpuID) REFERENCES Hardware(HardwareID) ON DELETE CASCADE
);
CREATE TABLE RAM (
RamID INT PRIMARY KEY,
Tipo VARCHAR(50),
DimensioneGB INT,
FrequenzaMHz INT NOT NULL,
FOREIGN KEY fk_ram_hardware (RamID) REFERENCES Hardware(HardwareID) ON DELETE CASCADE
);
CREATE TABLE PSU (
PsuID INT PRIMARY KEY,
PotenzaWatt INT,
Certificazione VARCHAR(50),
FOREIGN KEY fk_psu_hardware (PsuID) REFERENCES Hardware(HardwareID) ON DELETE CASCADE
);
CREATE TABLE SchedaMadre (
SchedaMadreID INT PRIMARY KEY,
Socket VARCHAR(20),
Formato ENUM('E-ATX', 'ATX', 'MICRO-ATX', 'MINI-ATX') NOT NULL,
FOREIGN KEY fk_schedamadre_hardware (SchedaMadreID) REFERENCES Hardware(HardwareID) ON DELETE CASCADE
);
CREATE TABLE CasePC (
CasePcID INT PRIMARY KEY,
Formato VARCHAR(20),
isRGB BOOLEAN,
FOREIGN KEY fk_casepc_hardware (CasePcID) REFERENCES Hardware(HardwareID) ON DELETE CASCADE
);
CREATE TABLE Archiviazione ( -- (da specializzare)
ArchiviazioneID INT PRIMARY KEY,
CapacitaGB INT NOT NULL,
VelocitaMbs INT NOT NULL,
Tipo ENUM('HDD', 'SSD') NOT NULL,
FOREIGN KEY fk_archiviazione_hardware (ArchiviazioneID) REFERENCES Hardware(HardwareID) ON DELETE CASCADE
);
-- Categorie Periferica
CREATE TABLE Mouse (
MouseID INT PRIMARY KEY,
Tasti INT,
DPI INT,
FOREIGN KEY fk_mouse_periferica (MouseID) REFERENCES Periferica(PerifericaID) ON DELETE CASCADE
);
CREATE TABLE Tastiera (
TastieraID INT PRIMARY KEY,
Taglia VARCHAR(50),
Tipo VARCHAR(50),
FOREIGN KEY fk_tastiera_periferica (TastieraID) REFERENCES Periferica(PerifericaID) ON DELETE CASCADE
);
CREATE TABLE Monitor (
MonitorID INT PRIMARY KEY,
FrequenzaHz INT,
Risoluzione VARCHAR(20),
DimensioneInch FLOAT,
FOREIGN KEY fk_monitor_periferica (MonitorID) REFERENCES Periferica(PerifericaID) ON DELETE CASCADE
);
CREATE TABLE Cuffie (
CuffieID INT PRIMARY KEY,
Tipo VARCHAR(50),
FOREIGN KEY fk_cuffie_periferica (CuffieID) REFERENCES Periferica(PerifericaID) ON DELETE CASCADE
);
-- Categorie Archiviazione
CREATE TABLE HDD (
HddID INT PRIMARY KEY,
Rpm INT,
FOREIGN KEY fk_hdd_archiviazione (HddID) REFERENCES Archiviazione(ArchiviazioneID) ON DELETE CASCADE
);
CREATE TABLE SSD (
SsdID INT PRIMARY KEY,
Tipo VARCHAR(50),
FOREIGN KEY fk_ssd_archiviazione(SsdID) REFERENCES Archiviazione(ArchiviazioneID) ON DELETE CASCADE
);
CREATE TABLE Build (
BuildID INT PRIMARY KEY AUTO_INCREMENT,
Nome VARCHAR(100),
CpuID INT NOT NULL,
GpuID INT NOT NULL,
RamID INT NOT NULL,
PsuID INT NOT NULL,
SchedaMadreID INT NOT NULL,
CasePcID INT NOT NULL,
ArchiviazioneID INT NOT NULL,
CuffieID INT,
MonitorID INT,
MouseID INT,
TastieraID INT,
TotalPrice DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
FOREIGN KEY fk_build_cpu (CpuID) REFERENCES CPU(CpuID),
FOREIGN KEY fk_build_gpu (GpuID) REFERENCES GPU(GpuID),
FOREIGN KEY fk_build_ram (RamID) REFERENCES RAM(RamID),
FOREIGN KEY fk_build_psu (PsuID) REFERENCES PSU(PsuID),
FOREIGN KEY fk_build_scheda_madre (SchedaMadreID) REFERENCES SchedaMadre(SchedaMadreID),
FOREIGN KEY fk_build_case_pc (CasePcID) REFERENCES CasePC(CasePcID),
FOREIGN KEY fk_build_archiviazione (ArchiviazioneID) REFERENCES Archiviazione(ArchiviazioneID),
FOREIGN KEY fk_build_cuffie (CuffieID) REFERENCES Cuffie(CuffieID),
FOREIGN KEY fk_build_monitor (MonitorID) REFERENCES Monitor(MonitorID),
FOREIGN KEY fk_build_mouse (MouseID) REFERENCES Mouse(MouseID),
FOREIGN KEY fk_build_tastiera (TastieraID) REFERENCES Tastiera(TastieraID)
);
CREATE TABLE Carrello (
CarrelloItemID INT PRIMARY KEY AUTO_INCREMENT, -- Chiave primaria semplice
ClienteID INT NOT NULL,
ProdottoID INT NOT NULL,
Quantita INT NOT NULL,
BuildID INT NULL, -- Può essere NULL per i prodotti singoli
-- Vincolo di unicità per la combinazione di cliente, prodotto e contesto (build o singolo)
-- Questo permette (5, 101, NULL) e (5, 101, 1) di coesistere
UNIQUE INDEX uq_item_in_cart (ClienteID, ProdottoID, BuildID),
FOREIGN KEY fk_carrello_cliente (ClienteID) REFERENCES Cliente(ClienteID) ON DELETE CASCADE,
FOREIGN KEY fk_carrello_prodotto (ProdottoID) REFERENCES Prodotto(ProdottoID) ON DELETE CASCADE,
-- La FK su BuildID ora funziona perché la colonna è nullable
FOREIGN KEY fk_carrello_build (BuildID) REFERENCES Build(BuildID) ON DELETE SET NULL
);
-- Build private (create dal cliente)
CREATE TABLE BuildPrivata (
BuildPrivataID INT PRIMARY KEY,
ClienteID INT,
FOREIGN KEY fk_buildprivata_build (BuildPrivataID) REFERENCES Build(BuildID) ON DELETE CASCADE,
FOREIGN KEY fk_buildprivata_cliente (ClienteID) REFERENCES Cliente(ClienteID) ON DELETE CASCADE
);
-- Build pubblica (creata dagli admin)
CREATE TABLE BuildPubblica (
BuildPubblicaID INT PRIMARY KEY,
Sconto DECIMAL(5,2),
FOREIGN KEY fk_buildpubblica_build (BuildPubblicaID) REFERENCES Build(BuildID) ON DELETE CASCADE
);
-- TABELLE DI ASSOCIAZIONE
-- Ordine <-> Acquisto <-> Prodotto
CREATE TABLE Acquisto (
OrdineID INT,
ProdottoID INT,
Quantita INT,
PrezzoSingolo DECIMAL(10,2),
PRIMARY KEY (OrdineID, ProdottoID),
FOREIGN KEY fk_acquisto_ordine (OrdineID) REFERENCES Ordine(OrdineID),
FOREIGN KEY fk_acquisto_prodotto (ProdottoID) REFERENCES Prodotto(ProdottoID)
);
-- INDICI
CREATE INDEX idx_prodotto_nome ON Prodotto(Nome);
CREATE INDEX idx_prodotto_marca ON Prodotto(Marca);
CREATE INDEX idx_hardware_categoria ON Hardware(CategoriaHardware);
CREATE INDEX idx_periferica_categoria ON Periferica(CategoriaPeriferica);
CREATE INDEX idx_ordine_data ON Ordine(DataOrdine);
-- =====================================================================
-- COMPLETE AND FINAL DATABASE TRIGGER SCRIPT
-- =====================================================================
-- This script contains all triggers for the application.
--
-- Key Improvements:
-- 1. All category coherence triggers now use the robust `COUNT(*)`
-- pattern to prevent errors and ensure data integrity.
-- 2. All data validation logic (for prices, quantities, etc.) is
-- centralized in Stored Procedures for easy maintenance.
-- 3. The script is idempotent: it drops all objects before creating
-- them, so it can be run multiple times without errors.
-- =====================================================================
-- Set the delimiter for multi-statement procedures and triggers
DELIMITER $$
-- ---------------------------------------------------------------------
-- SECTION 1: CLEANUP (DROP EXISTING OBJECTS)
-- ---------------------------------------------------------------------
-- Drop procedures first
DROP PROCEDURE IF EXISTS sp_check_strictly_positive_value;
DROP PROCEDURE IF EXISTS sp_check_non_negative_value;
DROP PROCEDURE IF EXISTS sp_check_sconto_range;
DROP PROCEDURE IF EXISTS sp_check_cap_format;
-- Drop all triggers
DROP TRIGGER IF EXISTS trg_check_prodotto_is_hardware;
DROP TRIGGER IF EXISTS trg_check_prodotto_is_periferica;
DROP TRIGGER IF EXISTS trg_check_hardware_is_cpu;
DROP TRIGGER IF EXISTS trg_check_hardware_is_gpu;
DROP TRIGGER IF EXISTS trg_check_hardware_is_ram;
DROP TRIGGER IF EXISTS trg_check_hardware_is_psu;
DROP TRIGGER IF EXISTS trg_check_hardware_is_mobo;
DROP TRIGGER IF EXISTS trg_check_hardware_is_casepc;
DROP TRIGGER IF EXISTS trg_check_hardware_is_storage;
DROP TRIGGER IF EXISTS trg_check_storage_is_hdd;
DROP TRIGGER IF EXISTS trg_check_storage_is_ssd;
DROP TRIGGER IF EXISTS trg_check_peripheral_is_mouse;
DROP TRIGGER IF EXISTS trg_check_peripheral_is_keyboard;
DROP TRIGGER IF EXISTS trg_check_peripheral_is_monitor;
DROP TRIGGER IF EXISTS trg_check_peripheral_is_headset;
DROP TRIGGER IF EXISTS trg_prezzo_prodotto_insert;
DROP TRIGGER IF EXISTS trg_prezzo_prodotto_update;
DROP TRIGGER IF EXISTS trg_quantita_prodotto_insert;
DROP TRIGGER IF EXISTS trg_quantita_prodotto_update;
DROP TRIGGER IF EXISTS trg_quantita_carrello_insert;
DROP TRIGGER IF EXISTS trg_quantita_carrello_update;
DROP TRIGGER IF EXISTS trg_quantita_acquisto_insert;
DROP TRIGGER IF EXISTS trg_quantita_acquisto_update;
DROP TRIGGER IF EXISTS trg_capacita_archiviazione_insert;
DROP TRIGGER IF EXISTS trg_capacita_archiviazione_update;
DROP TRIGGER IF EXISTS trg_sconto_prodotto_insert;
DROP TRIGGER IF EXISTS trg_sconto_prodotto_update;
DROP TRIGGER IF EXISTS trg_sconto_buildpubblica_insert;
DROP TRIGGER IF EXISTS trg_sconto_buildpubblica_update;
DROP TRIGGER IF EXISTS trg_cap_cliente_insert;
DROP TRIGGER IF EXISTS trg_cap_cliente_update;
DROP TRIGGER IF EXISTS trg_cap_ordine_insert;
DROP TRIGGER IF EXISTS trg_cap_ordine_update;
DROP TRIGGER IF EXISTS trg_build_before_insert_set_price;
DROP TRIGGER IF EXISTS trg_product_after_update_recalculate_build_prices;
DROP FUNCTION IF EXISTS CalculateBuildTotalPrice;
-- ---------------------------------------------------------------------
-- SECTION 2: STORED PROCEDURES FOR VALIDATION
-- ---------------------------------------------------------------------
CREATE PROCEDURE sp_check_strictly_positive_value(IN val DECIMAL(10,2), IN msg VARCHAR(255))
BEGIN
IF val IS NOT NULL AND val <= 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
END IF;
END$$
CREATE PROCEDURE sp_check_non_negative_value(IN val INT, IN msg VARCHAR(255))
BEGIN
IF val IS NOT NULL AND val < 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
END IF;
END$$
CREATE PROCEDURE sp_check_sconto_range(IN sconto DECIMAL(5,2))
BEGIN
IF sconto IS NOT NULL AND (sconto < 0 OR sconto > 100) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Sconto deve essere compreso tra 0 e 100';
END IF;
END$$
CREATE PROCEDURE sp_check_cap_format(IN cap CHAR(5), IN is_nullable BOOLEAN)
BEGIN
IF cap IS NOT NULL AND cap NOT REGEXP '^[0-9]{5}$' THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'CAP deve essere composto da esattamente 5 cifre numeriche';
END IF;
IF NOT is_nullable AND cap IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'CAP non può essere nullo';
END IF;
END$$
-- TOTALPRICE per Build
CREATE FUNCTION CalculateBuildTotalPrice(
p_cpuID INT, p_gpuID INT, p_ramID INT, p_psuID INT, p_moboID INT, p_caseID INT, p_storageID INT,
p_mouseID INT, p_monitorID INT, p_cuffieID INT, p_tastieraID INT
)
RETURNS DECIMAL(10, 2)
DETERMINISTIC
BEGIN
DECLARE total_price DECIMAL(10, 2) DEFAULT 0.00;
-- Somma i prezzi dei componenti usando gli ID passati come parametri
-- Usiamo una subquery per evitare di leggere direttamente dalla tabella Prodotto
-- all'interno di una singola istruzione complessa, che a volte può confondere MySQL.
SELECT SUM(Prezzo) INTO total_price FROM Prodotto
WHERE ProdottoID IN (
p_cpuID, p_gpuID, p_ramID, p_psuID, p_moboID, p_caseID, p_storageID,
IFNULL(p_mouseID, -1), IFNULL(p_monitorID, -1), IFNULL(p_cuffieID, -1), IFNULL(p_tastieraID, -1)
);
RETURN IFNULL(total_price, 0.00);
END$$
-- ---------------------------------------------------------------------
-- SECTION 3: TRIGGERS FOR CATEGORY COHERENCE (USING COUNT(*))
-- ---------------------------------------------------------------------
-- Prodotto -> Hardware
CREATE TRIGGER trg_check_prodotto_is_hardware BEFORE INSERT ON Hardware FOR EACH ROW
BEGIN
DECLARE n INT;
SELECT COUNT(*) INTO n FROM Prodotto WHERE ProdottoID = NEW.HardwareID AND CategoriaProdotto = 'Hardware';
IF n = 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Il prodotto non esiste o non è classificato come Hardware';
END IF;
END$$
-- Prodotto -> Periferica
CREATE TRIGGER trg_check_prodotto_is_periferica BEFORE INSERT ON Periferica FOR EACH ROW
BEGIN
DECLARE n INT;
SELECT COUNT(*) INTO n FROM Prodotto WHERE ProdottoID = NEW.PerifericaID AND CategoriaProdotto = 'Periferica';
IF n = 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Il prodotto non esiste o non è classificato come Periferica';
END IF;
END$$
-- Hardware -> Specializations
CREATE TRIGGER trg_check_hardware_is_cpu BEFORE INSERT ON CPU FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Hardware WHERE HardwareID = NEW.CpuID AND CategoriaHardware = 'CPU'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'L''hardware non è classificato come CPU'; END IF; END$$
CREATE TRIGGER trg_check_hardware_is_gpu BEFORE INSERT ON GPU FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Hardware WHERE HardwareID = NEW.GpuID AND CategoriaHardware = 'GPU'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'L''hardware non è classificato come GPU'; END IF; END$$
CREATE TRIGGER trg_check_hardware_is_ram BEFORE INSERT ON RAM FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Hardware WHERE HardwareID = NEW.RamID AND CategoriaHardware = 'RAM'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'L''hardware non è classificato come RAM'; END IF; END$$
CREATE TRIGGER trg_check_hardware_is_psu BEFORE INSERT ON PSU FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Hardware WHERE HardwareID = NEW.PsuID AND CategoriaHardware = 'PSU'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'L''hardware non è classificato come PSU'; END IF; END$$
CREATE TRIGGER trg_check_hardware_is_mobo BEFORE INSERT ON SchedaMadre FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Hardware WHERE HardwareID = NEW.SchedaMadreID AND CategoriaHardware = 'SchedaMadre'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'L''hardware non è classificato come SchedaMadre'; END IF; END$$
CREATE TRIGGER trg_check_hardware_is_casepc BEFORE INSERT ON CasePC FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Hardware WHERE HardwareID = NEW.CasePcID AND CategoriaHardware = 'CasePC'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'L''hardware non è classificato come CasePC'; END IF; END$$
CREATE TRIGGER trg_check_hardware_is_storage BEFORE INSERT ON Archiviazione FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Hardware WHERE HardwareID = NEW.ArchiviazioneID AND CategoriaHardware = 'Archiviazione'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'L''hardware non è classificato come Archiviazione'; END IF; END$$
-- Archiviazione -> Specializations
CREATE TRIGGER trg_check_storage_is_hdd BEFORE INSERT ON HDD FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Archiviazione WHERE ArchiviazioneID = NEW.HddID AND Tipo = 'HDD'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'L''archiviazione non è classificata come HDD'; END IF; END$$
CREATE TRIGGER trg_check_storage_is_ssd BEFORE INSERT ON SSD FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Archiviazione WHERE ArchiviazioneID = NEW.SsdID AND Tipo = 'SSD'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'L''archiviazione non è classificata come SSD'; END IF; END$$
-- Periferica -> Specializations
CREATE TRIGGER trg_check_peripheral_is_mouse BEFORE INSERT ON Mouse FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Periferica WHERE PerifericaID = NEW.MouseID AND CategoriaPeriferica = 'Mouse'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La periferica non è classificata come Mouse'; END IF; END$$
CREATE TRIGGER trg_check_peripheral_is_keyboard BEFORE INSERT ON Tastiera FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Periferica WHERE PerifericaID = NEW.TastieraID AND CategoriaPeriferica = 'Tastiera'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La periferica non è classificata come Tastiera'; END IF; END$$
CREATE TRIGGER trg_check_peripheral_is_monitor BEFORE INSERT ON Monitor FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Periferica WHERE PerifericaID = NEW.MonitorID AND CategoriaPeriferica = 'Monitor'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La periferica non è classificata come Monitor'; END IF; END$$
CREATE TRIGGER trg_check_peripheral_is_headset BEFORE INSERT ON Cuffie FOR EACH ROW
BEGIN DECLARE n INT; SELECT COUNT(*) INTO n FROM Periferica WHERE PerifericaID = NEW.CuffieID AND CategoriaPeriferica = 'Cuffie'; IF n = 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'La periferica non è classificata come Cuffie'; END IF; END$$
DELIMITER $$
-- Trigger per l'inserimento di una nuova build
CREATE TRIGGER trg_build_before_insert_set_price
BEFORE INSERT ON Build
FOR EACH ROW
BEGIN
-- Calcola il prezzo usando i valori della nuova riga e lo imposta prima dell'inserimento
SET NEW.TotalPrice = CalculateBuildTotalPrice(
NEW.CpuID, NEW.GpuID, NEW.RamID, NEW.PsuID, NEW.SchedaMadreID, NEW.CasePcID, NEW.ArchiviazioneID,
NEW.MouseID, NEW.MonitorID, NEW.CuffieID, NEW.TastieraID
);
END$$
-- Trigger per l'aggiornamento di una build (se cambiano i componenti)
CREATE TRIGGER trg_build_before_update_set_price
BEFORE UPDATE ON Build
FOR EACH ROW
BEGIN
-- Calcola il prezzo usando i valori aggiornati e lo imposta prima dell'update
SET NEW.TotalPrice = CalculateBuildTotalPrice(
NEW.CpuID, NEW.GpuID, NEW.RamID, NEW.PsuID, NEW.SchedaMadreID, NEW.CasePcID, NEW.ArchiviazioneID,
NEW.MouseID, NEW.MonitorID, NEW.CuffieID, NEW.TastieraID
);
END$$
CREATE TRIGGER trg_product_after_update_recalculate_build_prices
AFTER UPDATE ON Prodotto
FOR EACH ROW
BEGIN
IF OLD.Prezzo <> NEW.Prezzo THEN
-- Questo è un approccio più complesso ma che aggira le restrizioni di MySQL.
-- Aggiorniamo la tabella Build unendola a tutte le tabelle dei prodotti
-- per ricalcolare la somma al volo.
UPDATE Build b
JOIN (
SELECT
b_inner.BuildID,
SUM(p_cpu.Prezzo + p_gpu.Prezzo + p_ram.Prezzo + p_psu.Prezzo + p_mobo.Prezzo + p_case.Prezzo + p_storage.Prezzo +
IFNULL(p_mouse.Prezzo, 0) + IFNULL(p_monitor.Prezzo, 0) + IFNULL(p_cuffie.Prezzo, 0) + IFNULL(p_tastiera.Prezzo, 0)) as NewTotal
FROM Build b_inner
JOIN Prodotto p_cpu ON b_inner.CpuID = p_cpu.ProdottoID
JOIN Prodotto p_gpu ON b_inner.GpuID = p_gpu.ProdottoID
JOIN Prodotto p_ram ON b_inner.RamID = p_ram.ProdottoID
JOIN Prodotto p_psu ON b_inner.PsuID = p_psu.ProdottoID
JOIN Prodotto p_mobo ON b_inner.SchedaMadreID = p_mobo.ProdottoID
JOIN Prodotto p_case ON b_inner.CasePcID = p_case.ProdottoID
JOIN Prodotto p_storage ON b_inner.ArchiviazioneID = p_storage.ProdottoID
LEFT JOIN Prodotto p_mouse ON b_inner.MouseID = p_mouse.ProdottoID
LEFT JOIN Prodotto p_monitor ON b_inner.MonitorID = p_monitor.ProdottoID
LEFT JOIN Prodotto p_cuffie ON b_inner.CuffieID = p_cuffie.ProdottoID
LEFT JOIN Prodotto p_tastiera ON b_inner.TastieraID = p_tastiera.ProdottoID
WHERE b_inner.CpuID = NEW.ProdottoID OR b_inner.GpuID = NEW.ProdottoID OR b_inner.RamID = NEW.ProdottoID OR
b_inner.PsuID = NEW.ProdottoID OR b_inner.SchedaMadreID = NEW.ProdottoID OR b_inner.CasePcID = NEW.ProdottoID OR
b_inner.ArchiviazioneID = NEW.ProdottoID OR b_inner.MouseID = NEW.ProdottoID OR b_inner.MonitorID = NEW.ProdottoID OR
b_inner.CuffieID = NEW.ProdottoID OR b_inner.TastieraID = NEW.ProdottoID
GROUP BY b_inner.BuildID
) AS recalculated ON b.BuildID = recalculated.BuildID
SET b.TotalPrice = recalculated.NewTotal;
END IF;
END$$
-- ---------------------------------------------------------------------
-- SECTION 4: TRIGGERS FOR DATA VALIDATION (USING PROCEDURES)
-- ---------------------------------------------------------------------
-- --- Prezzo ---
CREATE TRIGGER trg_prezzo_prodotto_insert BEFORE INSERT ON Prodotto FOR EACH ROW
BEGIN CALL sp_check_strictly_positive_value(NEW.Prezzo, 'Il prezzo del prodotto deve essere positivo'); END$$
CREATE TRIGGER trg_prezzo_prodotto_update BEFORE UPDATE ON Prodotto FOR EACH ROW
BEGIN CALL sp_check_strictly_positive_value(NEW.Prezzo, 'Il prezzo del prodotto deve essere positivo'); END$$
-- --- Quantita ---
CREATE TRIGGER trg_quantita_prodotto_insert BEFORE INSERT ON Prodotto FOR EACH ROW
BEGIN CALL sp_check_non_negative_value(NEW.Quantita, 'La quantità del prodotto non può essere negativa'); END$$
CREATE TRIGGER trg_quantita_prodotto_update BEFORE UPDATE ON Prodotto FOR EACH ROW
BEGIN CALL sp_check_non_negative_value(NEW.Quantita, 'La quantità del prodotto non può essere negativa'); END$$
CREATE TRIGGER trg_quantita_carrello_insert BEFORE INSERT ON Carrello FOR EACH ROW
BEGIN CALL sp_check_strictly_positive_value(NEW.Quantita, 'La quantità nel carrello deve essere positiva'); END$$
CREATE TRIGGER trg_quantita_carrello_update BEFORE UPDATE ON Carrello FOR EACH ROW
BEGIN CALL sp_check_strictly_positive_value(NEW.Quantita, 'La quantità nel carrello deve essere positiva'); END$$
CREATE TRIGGER trg_quantita_acquisto_insert BEFORE INSERT ON Acquisto FOR EACH ROW
BEGIN CALL sp_check_strictly_positive_value(NEW.Quantita, 'La quantità acquistata deve essere positiva'); END$$
CREATE TRIGGER trg_quantita_acquisto_update BEFORE UPDATE ON Acquisto FOR EACH ROW
BEGIN CALL sp_check_strictly_positive_value(NEW.Quantita, 'La quantità acquistata deve essere positiva'); END$$
-- --- Capacita ---
CREATE TRIGGER trg_capacita_archiviazione_insert BEFORE INSERT ON Archiviazione FOR EACH ROW
BEGIN CALL sp_check_strictly_positive_value(NEW.CapacitaGB, 'La capacità di archiviazione deve essere positiva'); END$$
CREATE TRIGGER trg_capacita_archiviazione_update BEFORE UPDATE ON Archiviazione FOR EACH ROW
BEGIN CALL sp_check_strictly_positive_value(NEW.CapacitaGB, 'La capacità di archiviazione deve essere positiva'); END$$
-- --- Sconto ---
CREATE TRIGGER trg_sconto_prodotto_insert BEFORE INSERT ON Prodotto FOR EACH ROW
BEGIN CALL sp_check_sconto_range(NEW.Sconto); END$$
CREATE TRIGGER trg_sconto_prodotto_update BEFORE UPDATE ON Prodotto FOR EACH ROW
BEGIN CALL sp_check_sconto_range(NEW.Sconto); END$$
CREATE TRIGGER trg_sconto_buildpubblica_insert BEFORE INSERT ON BuildPubblica FOR EACH ROW
BEGIN CALL sp_check_sconto_range(NEW.Sconto); END$$
CREATE TRIGGER trg_sconto_buildpubblica_update BEFORE UPDATE ON BuildPubblica FOR EACH ROW
BEGIN CALL sp_check_sconto_range(NEW.Sconto); END$$
-- --- CAP ---
CREATE TRIGGER trg_cap_cliente_insert BEFORE INSERT ON Cliente FOR EACH ROW
BEGIN CALL sp_check_cap_format(NEW.CAP, TRUE); END$$
CREATE TRIGGER trg_cap_cliente_update BEFORE UPDATE ON Cliente FOR EACH ROW
BEGIN CALL sp_check_cap_format(NEW.CAP, TRUE); END$$
CREATE TRIGGER trg_cap_ordine_insert BEFORE INSERT ON Ordine FOR EACH ROW
BEGIN CALL sp_check_cap_format(NEW.CAPSpedizione, FALSE); END$$
CREATE TRIGGER trg_cap_ordine_update BEFORE UPDATE ON Ordine FOR EACH ROW
BEGIN CALL sp_check_cap_format(NEW.CAPSpedizione, FALSE); END$$
-- Reset the delimiter back to the default
DELIMITER ;