MySQL Trigger updating second table based on History and computed values
1
vote
1
answer
100
views
**The Goal:**
Update an secondary table called **Lottery_Cycle** when an INSERT occours on table **Lottery_History** with some computed values and checking previous data.
Let's say a lottery with 25 numbers of which 15 are drawn.
**What is an Cycle on this scenario?**
On this scenario a cycle consists of recording when all lottery numbers are drawn.
When this occurs, one cycle closes and another begins.
**Lottery_History structure**
CREATE TABLE IF NOT EXISTS Lottery_History
(
Id
SMALLINT(5) UNSIGNED NOT NULL,
Ball_01
TINYINT(3) UNSIGNED NOT NULL,
Ball_02
TINYINT(3) UNSIGNED NOT NULL,
Ball_03
TINYINT(3) UNSIGNED NOT NULL,
Ball_04
TINYINT(3) UNSIGNED NOT NULL,
Ball_05
TINYINT(3) UNSIGNED NOT NULL,
Ball_06
TINYINT(3) UNSIGNED NOT NULL,
Ball_07
TINYINT(3) UNSIGNED NOT NULL,
Ball_08
TINYINT(3) UNSIGNED NOT NULL,
Ball_09
TINYINT(3) UNSIGNED NOT NULL,
Ball_10
TINYINT(3) UNSIGNED NOT NULL,
Ball_11
TINYINT(3) UNSIGNED NOT NULL,
Ball_12
TINYINT(3) UNSIGNED NOT NULL,
Ball_13
TINYINT(3) UNSIGNED NOT NULL,
Ball_14
TINYINT(3) UNSIGNED NOT NULL,
Ball_15
TINYINT(3) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
*Id* = The contest number
*Ball_01* ~ Ball_15 = Each of the balls drawn in the contest
**Lottery_Cycle**
CREATE TABLE IF NOT EXISTS Lottery_Cycle
(
Id
SMALLINT(5) UNSIGNED NOT NULL,
Ball_Missing_01
TINYINT(1) UNSIGNED DEFAULT NULL,
Ball_Missing_02
TINYINT(1) UNSIGNED DEFAULT NULL,
Ball_Missing_03
TINYINT(1) UNSIGNED DEFAULT NULL,
Ball_Missing_04
TINYINT(1) UNSIGNED DEFAULT NULL,
Ball_Missing_05
TINYINT(1) UNSIGNED DEFAULT NULL,
Ball_Missing_06
TINYINT(1) UNSIGNED DEFAULT NULL,
Ball_Missing_07
TINYINT(1) UNSIGNED DEFAULT NULL,
Ball_Missing_08
TINYINT(1) UNSIGNED DEFAULT NULL,
Ball_Missing_09
TINYINT(1) UNSIGNED DEFAULT NULL,
Ball_Missing_10
TINYINT(1) UNSIGNED DEFAULT NULL,
Missing
TINYINT(1) UNSIGNED AS (
(Ball_Missing_01
IS NOT NULL) +
(Ball_Missing_02
IS NOT NULL) +
(Ball_Missing_03
IS NOT NULL) +
(Ball_Missing_04
IS NOT NULL) +
(Ball_Missing_05
IS NOT NULL) +
(Ball_Missing_06
IS NOT NULL) +
(Ball_Missing_07
IS NOT NULL) +
(Ball_Missing_08
IS NOT NULL) +
(Ball_Missing_09
IS NOT NULL) +
(Ball_Missing_10
IS NOT NULL)
),
Contests
TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
Cycle
SMALLINT(1) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
*Id* = The contest number
*Ball_Missing_01* ~ *Ball_Missing_10* = Displays balls not yet drawn in the cycle
*Missing* = It is a computed column that reports the total number of balls not drawn
*Contests* = Informs the number of contests in the current cycle
*Cycle* = Displays the cycle number
**Example use case and desired behavior**
Lottery Competition 1, the following numbers were drawn and entered in the table **Lottery_History**:
01 05 06 08 09 10 13 15 16 17 18 19 20 22 25
Therefore, the Cycle Table must have the following values:
Id = 1
Ball_Missing_01 = 02
Ball_Missing_02 = 03
Ball_Missing_03 = 04
Ball_Missing_04 = 07
Ball_Missing_05 = 11
Ball_Missing_06 = 12
Ball_Missing_07 = 14
Ball_Missing_08 = 21
Ball_Missing_09 = 23
Ball_Missing_10 = 24
Quantity = Automatically computed (will be 10)
Contest = 1
Cycle = 1
Lottery Competition 2, the following numbers were drawn and entered in the table **Lottery_History**:
03 04 05 09 10 11 13 15 16 17 19 20 21 24 25
Therefore, the Cycle Table must have the following values:
Id = 2
Ball_Missing_01 = 02
Ball_Missing_02 = 07
Ball_Missing_03 = 12
Ball_Missing_04 = 14
Ball_Missing_05 = 23
Ball_Missing_06 = NULL
Ball_Missing_07 = NULL
Ball_Missing_08 = NULL
Ball_Missing_09 = NULL
Ball_Missing_10 = NULL
Quantity = Automatically computed (will be 5)
Contest = 2
Cycle = 1
Note that the Ball_Missing_01 ~ Ball_Missing_05 field refers to the 5 numbers out of the 25 possible that have not yet been drawn in either contest 1 and 2.
Full drawn numbers from contest 1 and 2:
01 03 04 05 06 08 09 10 11 13 15 16 17 18 19 20 21 22 24 25
The "Contest" field informs that it is the second competition in Cycle 1 with missing numbers (not yet drawn).
Lottery Competition 3, the following numbers were drawn and entered in the table **Lottery_History**:
02 03 04 05 06 08 09 10 11 12 14 19 20 23 24
Therefore, the Cycle Table must have the following values:
Id = 3
Ball_Missing_01 = 07
Ball_Missing_02 = NULL
Ball_Missing_03 = NULL
Ball_Missing_04 = NULL
Ball_Missing_05 = NULL
Ball_Missing_06 = NULL
Ball_Missing_07 = NULL
Ball_Missing_08 = NULL
Ball_Missing_09 = NULL
Ball_Missing_10 = NULL
Quantity = Automatically computed (will be 1)
Contest = 3
Cycle = 1
Lottery Competition 4, the following numbers were drawn and entered in the table **Lottery_History**:
02 06 07 08 09 10 11 12 16 19 20 22 23 24 25
Therefore, the Cycle Table must have the following values:
Id = 4
Ball_Missing_01 = NULL
Ball_Missing_02 = NULL
Ball_Missing_03 = NULL
Ball_Missing_04 = NULL
Ball_Missing_05 = NULL
Ball_Missing_06 = NULL
Ball_Missing_07 = NULL
Ball_Missing_08 = NULL
Ball_Missing_09 = NULL
Ball_Missing_10 = NULL
Quantity = Automatically computed (will be zero)
Contest = 4
Cycle = 1
At this point, a Cycle is completed because in the 4 contests informed, all numbers from 1 to 25 were drawn, and a new cycle begins.
Lottery Competition 5, the following numbers were drawn and entered in the table **Lottery_History**:
01 02 04 05 07 08 09 10 11 12 14 16 17 24 25
Therefore, the Cycle Table must have the following values:
Id = 5
Ball_Missing_01 = 03
Ball_Missing_02 = 06
Ball_Missing_03 = 13
Ball_Missing_04 = 15
Ball_Missing_05 = 18
Ball_Missing_06 = 19
Ball_Missing_07 = 20
Ball_Missing_08 = 21
Ball_Missing_09 = 22
Ball_Missing_10 = 23
Quantity = Automatically computed (will be ten)
Contest = 1
Cycle = 2
Note that now the **Cycle** field receives the value of 2 because it is a new cycle and **Contest** field is 1 because its the first Contest from this new cycle.
And this process must continue whenever a new insertion occurs in the table **Lottery_History**.
Triggers I have made
1 - For determine the value to **Missing** field:
DROP TRIGGER IF EXISTS trg_BI_Lottery_Cycle_Missing
;
DELIMITER $$
CREATE TRIGGER trg_BI_Lottery_Cycle
BEFORE INSERT ON `Lottery_Cycle
FOR EACH ROW
BEGIN
IF NEW.Missing > 0 THEN
SET NEW.Missing = (SELECT MAX(Contests) + 1 FROM Lottery_Cycle);
ELSE
SET NEW.Missing = 1;
END IF;
END
$$
DELIMITER ;
2 - For determine the value to **Cycle** field:
DROP TRIGGER IF EXISTS trg_BI_Lottery_Cycle_Cycle
;
DELIMITER $$
CREATE TRIGGER trg_BI_Lottery_Cycle_Cycle
BEFORE INSERT ON Lottery_Cycle
FOR EACH ROW
BEGIN
SET NEW.Cicle = (SELECT MAX(Cycle IS NOT NULL) + 1 FROM Lottery_Cycle);
END
$$
DELIMITER ;
3 - Where I'm stuck!
DROP TRIGGER IF EXISTS trg_AI_Lottery_Cycle_Update_Lottery_Cycle
;
CREATE TRIGGER trg_AI_Lottery_Cycle_Update_Lottery_Cycle
AFTER INSERT ON Lottery_History
FOR EACH ROW
BEGIN
DECLARE Contest_Id TINYINT DEFAULT 1;
DECLARE Current_Cycle TINYINT DEFAULT 1;
DECLARE Contests_Total TINYINT DEFAULT 1; ????
DECLARE Ball_Missing_Insert_01 TINYINT DEFAULT NULL;
DECLARE Ball_Missing_Insert_02 TINYINT DEFAULT NULL;
DECLARE Ball_Missing_Insert_03 TINYINT DEFAULT NULL;
DECLARE Ball_Missing_Insert_04 TINYINT DEFAULT NULL;
DECLARE Ball_Missing_Insert_05 TINYINT DEFAULT NULL;
DECLARE Ball_Missing_Insert_06 TINYINT DEFAULT NULL;
DECLARE Ball_Missing_Insert_07 TINYINT DEFAULT NULL;
DECLARE Ball_Missing_Insert_08 TINYINT DEFAULT NULL;
DECLARE Ball_Missing_Insert_09 TINYINT DEFAULT NULL;
DECLARE Ball_Missing_Insert_10 TINYINT DEFAULT NULL;
-- Check if table is empty
IF (SELECT COUNT(*) AS Contests
FROM
Lottery_Cycle
WHERE
Contests IS NULL
) = 0 THEN SET Contest_Id = 1;
ELSE
SET Contest_Id = (SELECT MAX(Id) FROM Lottery_History);
END IF;
-- Get currently Cycle
SET Current_Cycle = (SELECT MAX(Cycle) FROM Lottery_Cycle);
-- Create an temporary table for simulate an array
CREATE TEMPORARY TABLE IF NOT EXISTS Lottery_Cycle_Insert_Temp (
Number TINYINT(1) UNSIGNED NOT NULL
);
-- Insert all numbers (1 to 25) into the temporary table
INSERT INTO Lottery_Cycle_Insert_Temp (Number)
VALUES (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);
-- Removing the 15 drawn balls from the temporary table
DELETE FROM Lottery_Cycle_Insert_Temp
WHERE Number IN (NEW.Ball_01, NEW.Ball_02, NEW.Ball_03, NEW.Ball_04, NEW.Ball_05,
NEW.Ball_06, NEW.Ball_07, NEW.Ball_08, NEW.Ball_09, NEW.Ball_10,
NEW.Ball_11, NEW.Ball_12, NEW.Ball_13, NEW.Ball_14, NEW.Ball_15);
-- Removing numbers already drawn in previous contests of the same
-- Cycle of the Lottery_Cycle table
DELETE FROM Lottery_Cycle_Insert_Temp
WHERE Number IN (
SELECT DISTINCT
IF(LC.Ball_Missing_01 IS NULL, NULL, LC.Ball_Missing_01),
IF(LC.Ball_Missing_02 IS NULL, NULL, LC.Ball_Missing_02),
IF(LC.Ball_Missing_03 IS NULL, NULL, LC.Ball_Missing_03),
IF(LC.Ball_Missing_04 IS NULL, NULL, LC.Ball_Missing_04),
IF(LC.Ball_Missing_05 IS NULL, NULL, LC.Ball_Missing_05),
IF(LC.Ball_Missing_06 IS NULL, NULL, LC.Ball_Missing_06),
IF(LC.Ball_Missing_07 IS NULL, NULL, LC.Ball_Missing_07),
IF(LC.Ball_Missing_08 IS NULL, NULL, LC.Ball_Missing_08),
IF(LC.Ball_Missing_09 IS NULL, NULL, LC.Ball_Missing_09),
IF(LC.Ball_Missing_10 IS NULL, NULL, LC.Ball_Missing_10)
FROM Lottery_Cycle LC
WHERE LC.Cycle = Current_Cycle
);
-- Storing remaining numbers in variables for Insert
SET Ball_Missing_Insert_01 = (SELECT Number FROM Lottery_Cycle_Insert_Temp ORDER BY Number DESC LIMIT 1);
DELETE FROM Lottery_Cycle_Insert_Temp WHERE Number = Ball_Missing_01;
SET Ball_Missing_Insert_02 = (SELECT Number FROM Lottery_Cycle_Insert_Temp ORDER BY Number DESC LIMIT 1);
DELETE FROM Lottery_Cycle_Insert_Temp WHERE Number = Ball_Missing_Insert_02;
SET Ball_Missing_Insert_03 = (SELECT Number FROM Lottery_Cycle_Insert_Temp ORDER BY Number DESC LIMIT 1);
DELETE FROM Lottery_Cycle_Insert_Temp WHERE Number = Ball_Missing_Insert_03;
SET Ball_Missing_Insert_04 = (SELECT Number FROM Lottery_Cycle_Insert_Temp ORDER BY Number DESC LIMIT 1);
DELETE FROM Lottery_Cycle_Insert_Temp WHERE Number = Ball_Missing_Insert_04;
SET Ball_Missing_Insert_05 = (SELECT Number FROM Lottery_Cycle_Insert_Temp ORDER BY Number DESC LIMIT 1);
DELETE FROM Lottery_Cycle_Insert_Temp WHERE Number = Ball_Missing_Insert_05;
SET Ball_Missing_Insert_06 = (SELECT Number FROM Lottery_Cycle_Insert_Temp ORDER BY Number DESC LIMIT 1);
DELETE FROM Lottery_Cycle_Insert_Temp WHERE Number = Ball_Missing_Insert_06;
SET Ball_Missing_Insert_07 = (SELECT Number FROM Lottery_Cycle_Insert_Temp ORDER BY Number DESC LIMIT 1);
DELETE FROM Lottery_Cycle_Insert_Temp WHERE Number = Ball_Missing_Insert_07;
SET Ball_Missing_Insert_08 = (SELECT Number FROM Lottery_Cycle_Insert_Temp ORDER BY Number DESC LIMIT 1);
DELETE FROM Lottery_Cycle_Insert_Temp WHERE Number = Ball_Missing_Insert_08;
SET Ball_Missing_Insert_09 = (SELECT Number FROM Lottery_Cycle_Insert_Temp ORDER BY Number DESC LIMIT 1);
DELETE FROM Lottery_Cycle_Insert_Temp WHERE Number = Ball_Missing_Insert_09;
SET Ball_Missing_Insert_10 = (SELECT Number FROM Lottery_Cycle_Insert_Temp ORDER BY Number DESC LIMIT 1);
DELETE FROM Lottery_Cycle_Insert_Temp WHERE Number = Ball_Missing_Insert_10;
-- Configuring the value of the Current Cycle Competitions field
SET Contests_Total = (SELECT MAX(Contests IS NOT NULL) +1 FROM Lottery_Cycle);
-- If new Cycle Begins
IF Ball_Missing_Insert_01 IS NULL AND
Ball_Missing_Insert_02 IS NULL AND
Ball_Missing_Insert_03 IS NULL AND
Ball_Missing_Insert_04 IS NULL AND
Ball_Missing_Insert_05 IS NULL AND
Ball_Missing_Insert_06 IS NULL AND
Ball_Missing_Insert_07 IS NULL AND
Ball_Missing_Insert_08 IS NULL AND
Ball_Missing_Insert_09 IS NULL AND
Ball_Missing_Insert_10 IS NULL THEN
SET Current_Cycle = Current_Cycle + 1;
END IF;
-- Insert remaining missing numbers into Lottery_Cycle
INSERT INTO Lottery_Cycle
(
Id
,
Ball_Missing_01
,
Ball_Missing_02
,
Ball_Missing_03
,
Ball_Missing_04
,
Ball_Missing_05
,
Ball_Missing_06
,
Ball_Missing_07
,
Ball_Missing_08
,
Ball_Missing_09
,
Ball_Missing_10
,
Contests
,
Cycle
) VALUES (
Contest_Id,
Ball_Missing_Insert_01,
Ball_Missing_Insert_02,
Ball_Missing_Insert_03,
Ball_Missing_Insert_04,
Ball_Missing_Insert_05,
Ball_Missing_Insert_06,
Ball_Missing_Insert_07,
Ball_Missing_Insert_08,
Ball_Missing_Insert_09,
Ball_Missing_Insert_10,
Contests_Total,
Current_Cycle
);
-- Drop the temporary table
DROP TEMPORARY TABLE IF EXISTS Lottery_Cycle_Insert_Temp;
END
$$
DELIMITER ;
I'm stucking on trial and error, sometimes got:
(conn=17034) Column 'Cycle' cannot be null
Other times got:
(conn=17049) Operand should contain 1 column(s)
And other erros.
Someone can point me what I'm doing wrong?
Thanks in advice!!!
Asked by Wisdom
(11 rep)
May 13, 2024, 11:19 PM
Last activity: May 14, 2024, 09:55 PM
Last activity: May 14, 2024, 09:55 PM