Recursive table SQL - mysql

I´m new to SQL so I´m sorry if I make some simple mistakes. Having said that, I wanted to create a recursive table but I´m not sure how.
I have this table:
CREATE TABLE employee(
employee_id INT NOT NULL ,
Bdate DATETIME,
address VARCHAR(80),
PRIMARY KEY(supervisor_number)
);
And I have a 1:N cardinality in which 1 supervisor can supervise N supervisees. That´s why i need a recursive table, because an employee can either be a supervisor or a supervisee.
I don´t know how to create the recursive table so if anyone knows how I would be extremely grateful!
If there´s anything that isn´t clear let me know.
Thanks!

create a table of relation , you can call it supervision;
it the new table , put 2 fields : supervisor and supervisee;
these two fields are foreign keys to the table Employee ;
for example, employee number 1 is a supervisor for the employee 2 and 3, you insert two lines in the new table :
insert into supervision (supervisor, supervisee) values (1, 2), (1, 3);

Possible realization.
The table
CREATE TABLE employee(
employee_id INT NOT NULL ,
Bdate DATETIME,
address VARCHAR(80),
PRIMARY KEY(employee_id),
supervisor_id INT,
FOREIGN KEY (supervisor_id) REFERENCES employee(employee_id)
ON DELETE SET NULL ON UPDATE CASCADE );
The triggers which checks for subordinates amount (the value of 3 is hardcoded)
CREATE TRIGGER tr_bi_check_subordinates_amount
BEFORE INSERT
ON employee
FOR EACH ROW
BEGIN
IF 3 <= ( SELECT COUNT(*)
FROM employee
WHERE supervisor_id = NEW.supervisor_id ) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'No available slots for specified supervisor';
END IF;
END
CREATE TRIGGER tr_bu_check_subordinates_amount
BEFORE UPDATE
ON employee
FOR EACH ROW
BEGIN
IF 3 <= ( SELECT COUNT(*)
FROM employee
WHERE supervisor_id = NEW.supervisor_id ) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'No available slots for specified supervisor';
END IF;
END
DEMO fiddle

Related

MySQL - How to constrain column A always mapping to the same value in column B

For this table schema:
CREATE TABLE my_table(id_code varchar(255), health_code varchar(255), exam_date date);
How to declare an efficient constraint to enforce column health_code always mapping to the same value in column id_code?
This is the expected behavior:
id_code
health_code
exam_date
constraint result
1
11
20220501
init data
2
22
20220501
init data
1
11
20220601
good, your id_code and health code are consistent with row #1
2
33
20220601
reject, you get a different health_code than row #2
You can't do this with a constraint, because constraints can't perform queries, which is how you would compare with other rows.
You can do it in a trigger.
CREATE TRIGGER check_codes BEFORE INSERT ON my_table
FOR EACH ROW
IF EXISTS (
SELECT *
FROM my_table
WHERE id_code = NEW.id_code AND health_code != NEW.health_code
)
THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Inconsistent id_code and health_code'
END IF;
You can have a similar BEFORE UPDATE trigger in case someone tries to change one of the codes to an invalid value.

check date in create table sql

edit: version 8.0.20
I'm learning sql just now, I try to fix it but I'm not able to do it.
I have 3 table
create table order(
id_order int primary key,
order_date date
);
create delivery(
id_delivery int primary key,
delivery_date date,
cod_order int,
foreign key (cod_order) references order(id_order)
);
create purchased_product(
id_product int,
cod_order int,
return_date date,
foreign key (cod_order) references order(id_order)
primary key (id_product, cod_order)
);
This is an easier scheme but it's enough.
The return_date must be less than delivery_date + 30 days
I tried to use a check on return_date but no work, so I created a view to select the delivered products only
create view product_order_delivery(date_delivered_product) as
select date_delivery
from purchased_product P right join (select date_delivery, id_order
from order right join delivery
on order.id_order = delivery.cod_order
where date_delivery is not null) OD
on P.cod_order = OD.id_order
and I tried again with check on return_date.
Can someone help me to understand how fix it?
thanks in advance :)
Two common options for solving this are:
Write a trigger to be sure the condition is true.
Write a user-defined function and use that in a check constraint.
An alternative method might suffice in your case. Change the definition of return_date so it is days_to_return. Then you can use a check constraint:
check (days_to_return between 0 and 30)
Of course, to get the actual date, you will need to join the two tables to fetch the delivery date.
EDIT:
The insert trigger would look something like this:
delimiter $$
create trigger trig_purchased_product_return_date
before insert on purchased_product
for each row
begin
select #delivery_date = delivery_date
from delivery d
where d.cod_order = new.cod_order;
if new.return_date < #delivery_date or new.return_date > #delivery_date + interval 30 day then
signal sqlstate '45000' set message_text = 'invalid return_date'
end if
end;
delimiter ;

I need to insert data into a table which consists of 1 primary (AUTO_INCREMENT ) and 3 foreign keys

Table containing 1 primary key and 3 foreign keys; Order_ID 'Customer_ID','Item_ID', 'DateTime_ID'
Now, the DateTime table is updated simultaneously as the row containing the previous "1 primary and 3 foreign keys" is inserted.
$sql1="INSERT INTO datetime (DateTime_ID, OrderDate, OrderTime) VALUES (NULL, CURRENT_DATE (), CURRENT_TIME() )" ;
But I am struggling to work out an INSERT INTO query.
This is what I have so far:
$sql2="INSERT INTO myorder VALUES ('NULL', menu_item WHERE item_id='$item', customer WHERE Customer_ID='$id' '$sql1')";
'$sql1' being a guess to insert the first query simultaneously.
Your example is not really clear but you may try something like this:
DECLARE p_datetime_id INTEGER;
DECLARE p_customer_id INTEGER;
DECLARE p_item_id INTEGER;
-- Initialize customer and item
SET p_customer_id = ...;
SET p_item_id = ...;
-- Create datetime element
INSERT INTO datetime (OrderDate, OrderTime)
VALUES (CURRENT_DATE(), CURRENT_TIME());
SET p_datetime_id = IDENTITY();
-- Create order element
INSERT INTO myorder (Customer_ID, Item_ID, DateTime_ID)
VALUES (p_customer_id, p_item_id, p_datetime_id);

Calculate column value from another column in another table

I have a table that contains the unit price and other details of each item in a store.
CREATE TABLE Item (Item_id CHAR(4), Description CHAR(40), Sizes CHAR(40), Weight REAL, Unit_price REAL, PRIMARY KEY(Item_id));
And another one that contains details of the items contained in each order.
CREATE TABLE Order_contains_items (Item_id CHAR(4), Order_no INT, Quantity_ordered INT, Ordered_price REAL, PRIMARY KEY(Item_id, Order_no), FOREIGN KEY(Order_no) REFERENCES Order(Order_no), FOREIGN KEY(Item_id) REFERENCES Item(Item_id));
Now I want to compute
Order_contains_items.Ordered_price = Item.Unit_price * Order_contains_items.Quantity_ordered WHERE Order_contains_items.Item_id = Item.Item_id
Note that I want it to be a part of the table itself and not as a different view or a query. How can I do this? I looked into triggers and other mechanisms for this but do they work for values in different tables especially with such constraints?
I tried the following trigger based on Column calculated from another column? :
CREATE TRIGGER Order_price BEFORE INSERT ON Order_contains_items
FOR EACH ROW BEGIN
SET NEW.Ordered_price = Item.Unit_price * NEW.Quantity_ordered
WHERE NEW.Item_id = Item.Item_i
END;
But it didn't seem to work
Here is how you can do that in MySQL (your question is tagged with both mysql and sql-server)
CREATE TRIGGER tg_bi_order_contains_items
BEFORE INSERT ON Order_contains_items
FOR EACH ROW
SET NEW.Ordered_price =
(
SELECT Unit_price * NEW.Quantity_ordered
FROM Item
WHERE Item_id = NEW.Item_id
LIMIT 1
);
CREATE TRIGGER tg_bu_order_contains_items
BEFORE UPDATE ON Order_contains_items
FOR EACH ROW
SET NEW.Ordered_price =
(
SELECT Unit_price * NEW.Quantity_ordered
FROM Item
WHERE Item_id = NEW.Item_id
LIMIT 1
);
Here is SQLFiddle demo

Mysql prevent insert after some date

Is possible prevent the insertion in a mysql table after some date and time?
for example i have 2 tables:
TABLE exams
(
...
examID int primary key auto_increment,
examDate DATE,
examTime TIME,
...
)
TABLE inscripts
(
...
examID int not null references exams(examID),
insDate DATE,
insTime TIME,
...
)
i want to prevent the insertion of new inscriptions when the exam is playing.
There are some function to prevent this or check easily if current date and current time are equal or bigger than the date and time in matches table?
You could create a trigger that validates the insert before proceeding. Pseudo-code, but something like:
DELIMITER |
CREATE TRIGGER `Stop_Insert_During_Exam`
BEFORE UPDATE ON `inscripts`
FOR EACH ROW
BEGIN
DECLARE msg VARCHAR(255);
-- Check
-- Test if an exam is going on. If so:
SET msg = "You cannot add an inscription while an exam is going on.';
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
-- /Check
END;
|
Looking at your table, you already know the examid when you try to insert an inscription. So you can just grab the exam before you insert the inscription and check if it is ongoing. If it is just dont insert it and if it is not then insert it.