I want to compare the sum of values in table one with the limit value in table 2 . I tried with constraint or triggers but did not work any help
As in the photo below there are 2 table
table 1 has 2 columns reserve and available
The in these columns come from users and the it must not excees more than the limit on second table ..
As example user can enter any amount where sum of all the column must be less than the limit
As of table one i can enter value in booked column that can be between 0 to the limit in table 2 but if the limit is reached then it cannot add more rows for that element
create table booked (room_id foreign key (room_id),
booked datetime, booked_seats int, remaining_seats);
create table rooms ( room_id primary key
room_size int);
booked seats are done by user, i have seperate trigger for that to ensure user enters corrected,
in want a trigger or something similar that will check the sum of all seats booked in the firsts table and compare with the room_size in second table.
if the sum is less that the size it will edit or else return error
create trigger test after insert on booked
begin
if sum of all (new.booked ) where the id is same > table2.limit then
....
end
For a quick and good answer you need more things than you provided a functioning example data for example
This Trigger will block any attempts to insert if the room_size is smaller than the the sumed up seats.
Please read the end there i explain, where you must put some work in
DELIMITER $$
CREATE TRIGGER check_roomsize_Before_Insert BEFORE insert on booked
FOR EACH ROW
begin
if (SELECT SUM(booked_seats) + NEW.booked_seats FROM booked WHERE room_id = NEW.room_id AND booked = NEW.booked GROUP BY room_id)
> (select room_size from rooms where rooms.room_id= new.room_id) then
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Roomsize too smal!';
end if;
END$$
DELIMITER ;
Schema (MySQL v5.7)
create table rooms ( room_id int primary key,
room_size int);
create table booked (room_id int,
booked datetime, booked_seats int, remaining_seats int, CONSTRAINT fk_category
FOREIGN KEY (room_id)
REFERENCES rooms(room_id));
INSERT INTO rooms VALUES ( 1,5);
DELIMITER $$
CREATE TRIGGER check_roomsize_Before_Insert BEFORE insert on booked
FOR EACH ROW
begin
if (SELECT SUM(booked_seats) + NEW.booked_seats FROM booked WHERE room_id = NEW.room_id AND booked = NEW.booked GROUP BY room_id)
> (select room_size from rooms where rooms.room_id= new.room_id) then
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Roomsize too smal!';
end if;
END$$
DELIMITER ;
INSERT INTO booked VALUES (1,now(),3,2);
#INSERT INTO booked VALUES (1,now(),3,0);
Query #1
SELECT * FROM booked;
| room_id | booked | booked_seats | remaining_seats |
| ------- | ------------------- | ------------ | --------------- |
| 1 | 2020-04-19 20:04:07 | 3 | 2 |
View on DB Fiddle
As you can see in the example 1 row is inserted and the second, gives an exception.
you need to improve the part where i sum up the booked seats there i make a
AND booked = NEW.booked
Because i don't know absolutely what time criteria will count to sum the complete seats number. The now timestamp makes no sense put to test the trigger i need some date.
Related
I have 3 Mysql tables and I want to make one of the fields generated from multiplying two fields from two different tables. These are my tables:
ITEMS
id_item | price
1 | 20
2 | 30
3 | 50
DETAIL TRANSACTIONS
id_trans(fk) | id_item | total_items
1 | 1 | 1
1 | 2 | 1
1 | 3 | 1
TRANSACTIONS
id_trans | total_price
1 | 100
A total price field inside TRANSACTIONS is what I wanted, and I have tried making a trigger like:
CREATE TRIGGER total_price
AFTER INSERT ON detail_transactions
FOR EACH ROW
UPDATE transactions
SET transactions.`total_price`=
(SELECT SUM(items.'price'*detail_transactions.'total_items')
FROM items
JOIN detail_transactions
ON items.'id_item'= detail_transactions.`id_item`)
WHERE transactions.`id_trans` = NEW.`id_trans`;
But the result is not what I wanted. Any help will be appreciated!
Key words are FOR EACH ROW - ie update 1 row at a time..And do not assume transactions exists test and create if need be
drop trigger if exists t;
delimiter $$
create trigger t after insert on detail_transactions
for each row begin
if not exists (select 1 from transactions t where t.id_trans = new.id_trans) then
insert into transactions
select new.id_trans,new.total_items * price
from items
where items.id_item = new.id_item ;
else
update transactions join items on items.id_item = new.id_item
set total_price = total_price + (new.total_items * price);
end if;
end $$
CREATE TRIGGER tr_ai_update_total_price
AFTER INSERT
ON detail_transactions
FOR EACH ROW
REPLACE INTO transactions (id_trans, total_price)
SELECT NEW.id_trans, SUM(items.price * detail_transactions.total_items)
FROM items
JOIN detail_transactions USING (id_item)
WHERE transactions.id_trans = NEW.id_trans;
This query assumes that transactions (id_trans) is defined as UNIQUE (maybe PRIMARY KEY).
If the row for this id_trans already exists it will be replaced with new values. If it not exists then it will be inserted.
The trigger creation statement contains 1 statement, so neither BEGIN-END nor DELIMITER needed.
Im trying to implement an SQL Trigger that will UPDATE instead of INSERTing if the value of one column hasent change..
Example Table
Id | Name | Income | Date
11 John 10000 2019-02-01
11 John 15000 2019-02-02
This table does not have a Primary Key, because it will have multiple records for the same ID, each one with a diferent date. What I want to achive to save some space is to UPDATE instead of INSERT if the Income hasent changed... for example, if the next record is going to be:
11 John 15000 2019-02-03
I want the trigger to UPDATE the DATE instead of creating a new Record on the Table. So it will end up like:
11 John 10000 2019-02-01
11 John 15000 2019-02-03 <-- Changed!
The data comes from an hourly table that records the incomes from the day... and at the end of the day does a massive insert of all records on the hourly table to the incomes table to keep the history.
I tried the following trigger but it did not work since it does a lock.
DELIMITER //
CREATE TRIGGER before_insert_income
BEFORE INSERT ON income_30
FOR EACH ROW
BEGIN
IF NEW.income = (select income from income_30 where ID=NEW.ID and date=(select max(date) from income_30)) THEN
UPDATE income_30 set date = NEW.date where ID=NEW.ID;
END IF;
END; //
DELIMITER ;
I also though about doing an UPDATE instead of INSERT and perform a trigger that will do the opposite, will insert a new record if the income changed, but I didn't know which column could I make primary for the update.
I Apologise if it is a silly question, but its being bothering me for a while.
Thanks a lot!
If you only care about saving space I think you should only delete last month with the same income record just before you try to insert new income, with same amount.
DELIMITER //
CREATE TRIGGER before_insert_income
BEFORE INSERT ON income_30
FOR EACH ROW
BEGIN
IF NEW.income = (select income from income_30 where ID=NEW.ID and date=(select max(date) from income_30)) THEN
DELETE FROM income_30 where id=NEW.id and date=(select max(date) from income_30);
END IF;
END; //
DELIMITER;
PURCHASE TABLE
id (Primary Key) ItemNo, ItemName, Units, Qty, Location, CPrice,
SPrice, Supplier, PONo
STOCK TABLE
id (Primary Key), ItemNo, Qty, Location
IF EXISTS (SELECT ItemNo, Location FROM stock WHERE stock.ItemNo = 'poitem.ItemNo' AND stock.Location = 'poitem.Location') THEN
UPDATE stock SET stock.Qty = stock.Qty + poitem.Qty WHERE stock.ItemNo = 'poitem.ItemNo';
ELSE
INSERT INTO stock (stock.ItemNo, stock.Qty, stock.Location) SELECT poitem.ItemNo, poitem.Qty, poitem.Location FROM poitem;
END If
THis is my Code, but its not working as it should be
I need to update stock table when i enter a record through purchase table only is the record already exists, otherwise new record need to be entered.
Example:
ItemNo - Qty - Location
1001 - - - 15 - - - A
1001 - - - 12 - - - B
1002 - - - 50 - - - C
1003 - - - 12 - - - A
Can any one please write MYSQL code for this.
Thank you.
Your if exists will always evaluate to true (unless the stock table is empty) so the update will never happen (unless the stock table is empty). I think a procedure is inappropriate here unless you are calling it for every insert. Even if you are a trigger is probably a better bet.
drop trigger if exists t;
delimiter $$
create trigger t after insert on poitems
for each row
begin
IF EXISTS (SELECT ItemNo, Location FROM stock WHERE stock.ItemNo = new.ItemNo AND stock.Location = new.Location) THEN
UPDATE stock SET stock.Qty = stock.Qty + new.Qty WHERE stock.ItemNo = new.ItemNo and stock.Location = new.Location;
ELSE INSERT INTO stock (ItemNo, Qty, Location) values(new.ItemNo, new.Qty, new.Location) ;
END If;
end $$
I have also amended your update statement to match the if exists clause and fixed the insert statement and a few other things which looked wrong.
so given
drop table if exists poitems,stock;
create TABLE poitems(id int auto_increment Primary Key, ItemNo int, ItemName varchar(10), Units int, Qty int, Location int, CPrice int
, SPrice int, Supplier int, PONo int);
create table stock(id int auto_increment Primary Key ,ItemNo int, Qty int, Location int);
insert into poitems(itemno,qty,location) values (1,1,1),(1,1,1),(2,2,1);
results in
+----+--------+------+----------+
| id | ItemNo | Qty | Location |
+----+--------+------+----------+
| 1 | 1 | 2 | 1 |
| 2 | 2 | 2 | 1 |
+----+--------+------+----------+
2 rows in set (0.00 sec)
Table Product
id name price quantity total
1 food 50 1 50
2 drink 20 2 40
3 dress 100 3 300
How do I declare a table that has a column that is the product of two columns?
I have this code:
CREATE TABLE [dbo].[Orders] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[ProductName] NCHAR (70) NULL,
[Price] INT NULL,
[Quantity] INT NULL,
[Total] INT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
Sounds like you want a VIEW.
Their example is exactly what you're describing
mysql> CREATE TABLE t (qty INT, price INT);
mysql> INSERT INTO t VALUES(3, 50);
mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql> SELECT * FROM v;
+------+-------+-------+
| qty | price | value |
+------+-------+-------+
| 3 | 50 | 150 |
+------+-------+-------+
You can try this mate:
DROP TRIGGER IF EXISTS trg_product_total;
DELIMITER //
CREATE TRIGGER trg_product_total AFTER INSERT ON product
FOR EACH ROW BEGIN
SET #price = NULL, #quantity = NULL;
SELECT price INTO #price FROM product
WHERE id = NEW.id;
SELECT quantity INTO #quantity
WHERE id = NEW.id;
UPDATE product SET total = #price * #quantity
WHERE id = NEW.id;
END;
You can use this kind of approach if you don't really want to process the product.total before inserting it into the DB.
The Trigger will execute each time a new record is added into the table, wherein the expected insert for the total column is either 'NULL' or '0' depending on your default value.
But I think it would be better if you calculate it before the insert.
The flow would be like:
Application side
1. get price and quantity for the product
2. calculate for the total
3. insert values into the query
4. execute query
In case you want to learn more about MySQL Trigger: Link
Also, PHP Transaction: Link
id | user_id | job_range | start_date | client_name| job_type | job_no | job_quan
1 | 4 | 1-3000 | 2014-05-13 | kenny's | coloured | t50000 | n4500
2 | 2 | 3001-4500 | 2014-05-13 | kenny's | coloured | t50000 | n4500
3 | 3 | 1-2000 | 2014-05-15 | fredy's | plain | t42100 | n5000
4 | 4 |2001-5000 | 2014-05-15 | fredy's | plain | t42100 | n5000
I want to write a query that uses range of numbers already inputted into the database (job_range) and matches it with a job_no to avoid another user from putting jobs in the job range into the database.
the number cannot be within the lower range already given. for any specific job, if there is a range of 1-2000 then you cannot add another row to the table for that job with the range starting between the 1-2000, only jobs from 2001 to 5000 can be picked. so user can only chose to do jobs btw range 2001 -5000
You have to make the column UNIQUE. You can do that by running this query (you'll need to delete duplicate entries first):
ALTER TABLE jobs ADD UNIQUE (desc)
Then when you try to run a query and the desc column already exists, it will return an error.
CREATE TABLE test_dup (id number, dup_from number,dup_to number);
create table dup_val_range (range_values NUMBER);
ALTER TABLE dup_val_range
ADD CONSTRAINT rng_unique unique (range_values);
CREATE SEQUENCE rng_seq
INCREMENT BY 1
START WITH 1
MINVALUE 1
MAXVALUE 9999999999999999999
NOCYCLE
NOCACHE
NOORDER;
create or replace procedure ins_rng(p_from IN NUMBER, p_to IN NUMBER)
AS
v_indx1 NUMBER;
BEGIN
IF p_from> p_to THEN
RAISE_APPLICATION_ERROR(-20001, 'from is Higher tham To');
END IF;
-- check for nulls
FOR i IN p_from..p_to
LOOP
BEGIN
insert into dup_val_range (range_values)
values (i);
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
rollback;
RAISE_APPLICATION_ERROR(-20001, 'Range ir taken!');
END;
END LOOP;
insert into test_dup
values (rng_seq.nextval,p_from,p_to);
END;
exec ins_rng(p_from=>1, p_to=>19);
exec ins_rng(p_from=>5, p_to=>20);
ORA-20001: Range ir taken!
select * from dup_val_range
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
select * from test_dup
3 1 19
But, if values wont be inserted through this proc ir will be added with hand this wont help..
As Marcell says, it isn't possible to use WHERE on an INSERT.
I'd be inclined to set a UNIQUE key on 'desc' based on your table layout and desired action, and then do a standard INSERT. If 1-300 has been inserted already, then the INSERT will fail with a duplicate key error that you can catch in your application.
ALTER TABLE `jobs` ADD UNIQUE (desc);
If you specify ON DUPLICATE KEY UPDATE, and a row is inserted that would cause a duplicate value in a UNIQUE index or PRIMARY KEY, an UPDATE of the old row is performed. For example, if column a is declared as UNIQUE and contains the value 1, the following two statements have identical effect:
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
UPDATE table SET c=c+1 WHERE a=1;
Here is the more detailed explanation and usage of ON DUPLICATE KEY
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
You want your INSERT to fail if some condition on the two values in your desc field isn't met.
First, as user2879235 mentions, the condition would be much easier to formulate if the desc field were split into two separate columns, let's call them start and end.
Another issue is with the meaning of the values in desc. Sometimes you only have 1 value, sometimes you have 2.
Is 1000 just a shorthand for 1000-1000 or is it something else? I will assume that it is.
And do 100-1000 and 1000-1100 conflict or do they not? I will assume that they do.
With these assumptions, I think your constraint can be formulated as (please verify this!)
NOT EXISTS (
SELECT j FROM jobs WHERE (j.start <= new.start AND j.end >= new.start)
OR (j.start <= new.end AND j.end >= new.end)
)
where new is the newly created tuple.
You want this constraint to be checked upon trying to insert, but MySQL doesn't support checking CHECK constraints, so you'll need to use a trigger instead in which you can raise a SIGNAL when the opposite of this constraint is met, which should roll back (i.e. undo) the INSERT.
one way you needed to split column (desc to desc_from and desc_to) or(substr string to get value from ,to) and you need check that from can't be greater than to and could use something like this..
CREATE TABLE test_dup (id number, dup_from number,dup_to number);
select * from test_dup;
ALTER TABLE test_dup
ADD CONSTRAINT chk_dup CHECK (dup_from<=dup_to);
insert into test_dup
select 1,2,300 from dual where not exists (select 1 from test_dup where 2<=dup_to AND 300>=dup_from);
insert into test_dup
select 2,4,399 from dual where not exists (select 1 from test_dup where 4<=dup_to AND 399>=dup_from);
insert into test_dup
select 3,1,500 from dual where not exists (select 1 from test_dup where 1<=dup_to AND 500>=dup_from);
insert into test_dup
select 4,301,304 from dual where not exists (select 1 from test_dup where 301<=dup_to AND 304>=dup_from);
insert into test_dup
select 4,200,200 from dual where not exists (select 1 from test_dup where 200<=dup_to AND 200>=dup_from);
insert into test_dup
select 4,555,555 from dual where not exists (select 1 from test_dup where 555<=dup_to AND 555>=dup_from);
select * from test_dup;
1 2 300
4 301 304
4 555 555
else ?you could use function based constraint where you put in same check, or not?
or one more you could create new check table and add unique counstraint. before you insert on real table you put all range of data into check table later catch error on dupval if there is
insert into test_dup
select 1,2,300 from dual where not exists (select 1 from test_dup where 2<=dup_to AND 300>=dup_from AND dup_from<dup_to);
one more
create or replace procedure insert_rng (p_id IN NUMBER, p_from IN NUMBER, p_to IN NUMBER)
AS
BEGIN
insert into test_dup
select p_id,p_from,p_to from dual where not exists (select 1 from test_dup where p_from<=dup_to AND p_to>=dup_from AND dup_from<=dup_to);
IF sql%notfound THEN
RAISE_APPLICATION_ERROR(-20001, 'range taken!');
END IF;
END;
exec insert_rng (p_id=>1, p_from=>1, p_to=>99);