So I have the following table:
CREATE TABLE Hospital_MedicalRecord(
recNo CHAR(5),
patient CHAR(9),
doctor CHAR(9),
enteredOn DATE NOT NULL,
diagnosis VARCHAR(50) NOT NULL,
treatment VARCHAR(50),
PRIMARY KEY (recNo, patient),
FOREIGN KEY (patient) REFERENCES Hospital_Patient(NINumber),
FOREIGN KEY (doctor) REFERENCES Hospital_Doctor(NINumber)
);
I want to make it so there are never more that 65,535 medical records for a single patient. Am I supposed to make a new statement or should I implement it in the table above. I can post the patient table if needed.
You would typically use a before insert trigger for this, that raises an error if the number of records for a patient reached the limit and a new insert is attempted:
delimiter //
create trigger Trg_Hospital_MedicalRecord
before insert on Hospital_MedicalRecord
for each row
begin
if (
select count(*) from Hospital_MedicalRecord where patient = new.patient
) = 65535 then
set msg = concat('Patient ', new.patient, ' cannot have more than 65535 records');
signal state '45000' set message_text = msg;
end if;
end
//
delimiter ;
I would assume that you should not allow a patient to be updated on an existing record. But if this may happen, then you also need a before update trigger (with the very same code).
Consider the following...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table(id SERIAL PRIMARY KEY, user_id INT NOT NULL);
INSERT INTO my_table (user_id)
SELECT 1
FROM (SELECT 1) x
LEFT
JOIN (SELECT user_id FROM my_table GROUP BY user_id HAVING COUNT(*) >=3) y
ON y.user_id = 1
WHERE y.user_id IS NULL
LIMIT 1;
This limits INSERTS to 3 per user_id.
Related
I created the following table called books:
CREATE TABLE IF NOT EXISTS `books` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I created another tablet called compare to compare any 2 books from the books table:
CREATE TABLE IF NOT EXISTS `compare` (
`id_1` BIGINT UNSIGNED NOT NULL,
`id_2` BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (`id_1`,`id_2`),
FOREIGN KEY (`id_1`) REFERENCES books(`id`),
FOREIGN KEY (`id_2`) REFERENCES books(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
The previous works as expected but I need to force MYSQL to allow ONLY unique combination of values in the compare table.
For example if I have the following row in compare table:
id_1 | id_2
------------
1 | 2
I want to force MYSQL to NOT allow me to insert the following row:
id_1 | id_2
------------
2 | 1
So I want MYSQL to allow only either 1,2 or 2,1 NOT both.
Another way would be to swap the values in a before-insert trigger to make sure id_1 < id_2:
CREATE TRIGGER `compare_before_insert` BEFORE INSERT ON `compare` FOR EACH ROW
BEGIN
DECLARE t BIGINT;
IF(NEW.id_1 > NEW.id_2) THEN
SET t = NEW.id_1;
SET NEW.id_1 = NEW.id_2;
SET NEW.id_2 = t;
END IF;
END
This will allow you to use the key to make the pairs unique.
In MySQL (at least prior to version 8), you need to do this using a trigger if you want the database to enforce the constraint.
delimiter $$
create trigger compare_insert_trigger before insert on compare
for each row
begin
if (exists (select 1
from compare c
where c.id2 = new.id1 and c.id1 = new.id2
)
) then
signal sqlsate '45000'
set message_text = 'Book pair already exists in compare';
end if;
end;$$
delimiter ;
Of course, you still need the unique constraint.
I want to implement a Viewed system for my website. Here is the structure of my tables:
// table1
id | user_or_ip | post_id | date_time // inserting new row for each viewed
// table2
id | post_id | total_viewed // getting the number of total viewed for each post
Now I need to a trigger for insert/update table2 after insert in table1.
I
think I have to use on duplicate key.
You can do this fairly easily.
With the following 2 example table:-
CREATE TABLE table1
(
id INT NOT NULL AUTO_INCREMENT,
user_or_ip VARCHAR(255),
post_id INT,
date_time DATETIME,
PRIMARY KEY (id)
);
CREATE TABLE table2
(
id INT NOT NULL AUTO_INCREMENT,
post_id INT,
total_viewed INT,
PRIMARY KEY (id),
UNIQUE KEY post_id (post_id)
);
you can use the following trigger on table 1 to calculate the count and insert it to table 2:-
CREATE TRIGGER `trig_1` AFTER INSERT ON `table1`
FOR EACH ROW BEGIN
INSERT INTO table2(post_id, total_viewed)
SELECT post_id, COUNT(*)
FROM table1
WHERE post_id = NEW.post_id
GROUP BY post_id
ON DUPLICATE KEY UPDATE total_viewed = VALUES(total_viewed);
END
Note that if you are certain that there will never be an error you could just insert a count of 1 and set it to total_count + 1 in the ON DUPLICATE KEY clause. But if anything fails that prevents the trigger the counts will be forever wrong for that post_id:-
CREATE TRIGGER `trig_1` AFTER INSERT ON `table1`
FOR EACH ROW BEGIN
INSERT INTO table2(post_id, total_viewed)
VALUES(NEW.post_id, 1)
ON DUPLICATE KEY UPDATE total_viewed = total_viewed + 1;
END
Note also that the sub query to get the count will be more efficient with an index on post_id in table1
I need to know that how to fetch a record from table which consist of certain records varies with different id named[sponser_id]
from the above img i give you a simple scenario..say for ex: the rounded person is said to be the person A.
when Person A loggin into his/her acc. It should show how many members(count) are coming under his/her control.
Mysql table has columns like
sponser_id refers to the parent user_id.
sponser_id varies with parent_user who referred them.
Here my question is, How to retrieve the count of members under this particular person..
I have only user_id & sponser_id columns alone in my table.
Here is an MLM tree I once implemented here, I think I deleted the answer cuz it was not appreciated :)
I always do these with Stored Procedures. A member can have a parent, like your setup.
The output showed downline sales and a commission at 5%
Schema
-- drop table member;
create table member
( memberId int not null auto_increment primary key,
handle varchar(255) not null,
parentId int null,
key (parentId)
);
-- drop table sales
create table sales
( -- sales of Products abbreviated
id int auto_increment primary key,
memberId int not null,
amount decimal(10,2) not null,
saleDate datetime not null,
CONSTRAINT `fk_member`
FOREIGN KEY (memberId)
REFERENCES member(memberId)
);
insert member(handle,parentId) values ('Johnny Two-Thumbs',null); -- 1
insert member(handle,parentId) values ('Jake the Enforcer',null); -- 2
insert member(handle,parentId) values ('Innocent Kim',2); -- 3
insert member(handle,parentId) values ('Karen',2); -- 4
insert member(handle,parentId) values ('Henry',2); -- 5
insert member(handle,parentId) values ('Shy Sales-less Sam',5); -- 6
insert member(handle,parentId) values ('Pete',5); -- 7
insert member(handle,parentId) values ('Iowa Mom',7); -- 8
insert member(handle,parentId) values ('Albuquerque Agoraphobiac',7); -- 9
insert sales (memberId,amount,saleDate) values (2,1,'2015-01-01');
insert sales (memberId,amount,saleDate) values (5,10,'2015-01-20');
insert sales (memberId,amount,saleDate) values (5,15.50,'2015-01-22');
insert sales (memberId,amount,saleDate) values (7,101.12,'2015-02-01');
insert sales (memberId,amount,saleDate) values (7,201.12,'2015-03-01');
insert sales (memberId,amount,saleDate) values (7,109,'2015-04-01');
insert sales (memberId,amount,saleDate) values (7,45,'2015-05-01');
insert sales (memberId,amount,saleDate) values (8,111,'2015-04-20');
insert sales (memberId,amount,saleDate) values (8,99.99,'2015-05-22');
insert sales (memberId,amount,saleDate) values (9,0.04,'2015-06-20');
insert sales (memberId,amount,saleDate) values (9,1.23,'2015-06-24');
Stored Procedure
drop procedure if exists showAllDownlineSales;
DELIMITER $$
create procedure showAllDownlineSales
(
theId int
)
BEGIN
-- theId parameter means i am anywhere in hierarchy of membership
-- and i want all downline sales
-- return 1 row: sales amt for downlines, and that amt * 5%, and total children (including children-of-children)
declare bDoneYet boolean default false;
declare working_on int;
declare theCount int;
declare downlineSales decimal(10,2);
declare commish decimal(10,2);
CREATE temporary TABLE xxFindSalesxx
(
memberId int not null,
processed int not null, -- 0 for not processed, 1 for processed
salesTotal decimal(10,2) not null
);
set bDoneYet=false;
insert into xxFindSalesxx (memberId,processed,salesTotal) select theId,0,0;
while (!bDoneYet) do
select count(*) into theCount from xxFindSalesxx where processed=0;
if (theCount=0) then
-- found em all
set bDoneYet=true;
else
-- one not processed yet, insert its children for processing
SELECT memberId INTO working_on FROM xxFindSalesxx where processed=0 limit 1;
insert into xxFindSalesxx (memberId,processed,salesTotal)
select memberId,0,0 from member
where parentId=working_on;
-- update xxFindSalesxx
-- join sales
-- on sales.memberId=xxFindSalesxx.memberId
-- set salesTotal=sum(sales.amount)
-- where xxFindSalesxx.memberId=working_on;
update xxFindSalesxx
set salesTotal=(select ifnull(sum(sales.amount),0) from sales where memberId=working_on)
where xxFindSalesxx.memberId=working_on;
-- mark the one we "processed for children" as processed
update xxFindSalesxx set processed=1 where memberId=working_on;
end if;
end while;
delete from xxFindSalesxx where memberId=theId;
select sum(salesTotal),count(*) into downlineSales,theCount from xxFindSalesxx;
drop table xxFindSalesxx;
select downlineSales,round(downlineSales*0.05,2) as commission,theCount; -- there is your answer, 1 row
END
$$
DELIMITER ;
Test it
call showAllDownlineSales(2); -- 693.00 34.69 7
call showAllDownlineSales(1); -- null null 0
call showAllDownlineSales(5); -- 668.50 33.43 4
I have a vet table and a medical table with a 1 to many relationship, and the ID's are auto incremented.
CREATE TABLE vet(
vetID INT NOT NULL AUTO_INCREMENT,
vetPractice varchar(35),
Address varchar(150),
contactNumber varchar (15),
PRIMARY KEY (VetID)
);
CREATE TABLE medical(
medicalID INT NOT NULL AUTO_INCREMENT,
medication VARCHAR (200),
PRIMARY KEY (medicalID),
FOREIGN KEY (vetID) REFERENCES vet(vetID)
);
Users can enter details of a vet, i want a query to determine;
if the the vet details entered already exist, then update the foreign key in vetID(medical) with the entered vetID.
else if the vet does not exist create a new vet and update the foreign key in vetID(medical) with the newly created vetID.
I have the following query
IF EXISTS(SELECT * FROM vet WHERE vetPractice = "inputValue")
THEN
UPDATE medical set value vetID = (Select max(vetID) from vet)
ELSE
INSERT INTO vet values (null, "newVetPractice", "NewAddress", "newContactNumber", "NewEmergencyNumber" );
Then
update medical set value vetID = (Select max(vetID) from vet);
END IF;
However, i am not familiar with if else's in mySQL is this the correct format, i have seen somethings about stored procedures.
Any help would be appreciate.
I'm not really clear about your logic; but it seems like you wanted it in a stored procedure format.
CREATE PROCEDURE 'sp_Med' (IN 'in_vetPractice' VARCHAR(35))
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
BEGIN
DECLARE ckExists int;
SET ckExists = 0;
SELECT count(*) INTO ckExists from vet WHERE vetPractice = in_vetPractice;
IF (ckExists > 0) THEN
UPDATE medical SET vetID = (Select max(vetID) FROM vet WHERE vetPractice = in_vetPractice)
ELSE
INSERT INTO vet VALUES (NULL, "newVetPractice", "NewAddress", "newContactNumber", "NewEmergencyNumber");
UPDATE medical SET vetID = LAST_INSERT_ID();
END IF;
END;
Execute it like
CALL sp_Med('newPractice')
I think you have to update your query, and this is the general syntax you have to use rather tha n yours:-
INSERT INTO `tableName` (`a`,`b`,`c`) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE `a`=VALUES(`a`), `b`=VALUES(`b`), `c`=VALUES(`c`);
This query will insert records if they are not present, and on presence it will update them.
So use this rather than your approach
I have 'users' table with the following fields:-
user_id (int, auto increment PK)
encrypted_userid (varchar 50)
user_name (varchar 50)
user_location (varchar 50)
What I want to do is create a trigger so that when values are inserted into the users table into user_name and user_location, i want to populate the encrypted_userid field with an AES_ENCRYPTED value from user_id - e.g. AES_ENCRYPT(user_id,'MYAESKEY') but only for the newly INSERTed row
Is this possible in MySQL with some kind of trigger?
Thanks in advance.
So is there a solution to my problem that will not fail etc? using a trigger - all other solutions i tried from reading other sources just didn't work.
Well all solutions revolve around LAST_INSERT_ID() because it's the only multi-user safe way to obtain auto generated ID.
First possible way, if you're very fond of triggers, is to have a separate table for auto generated sequences. Your schema will look like this
CREATE TABLE users_seq (user_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT);
CREATE TABLE users
(
user_id INT NOT NULL PRIMARY KEY DEFAULT 1,
encrypted_userid varchar(50),
user_name varchar(50),
user_location varchar(50),
FOREIGN KEY user_id_fk (user_id) REFERENCES users_seq (user_id)
);
And the trigger
DELIMITER //
CREATE TRIGGER useridinserttrigger
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
INSERT INTO users_seq() VALUES();
SET NEW.user_id = LAST_INSERT_ID(),
NEW.encrypted_userid = AES_ENCRYPT(LAST_INSERT_ID(), 'MYAESKEY');
END//
DELIMITER ;
Second way is to leverage your existing schema but use a stored procedure
DELIMITER //
CREATE PROCEDURE insert_user(IN _name VARCHAR(50), IN _location VARCHAR(50))
BEGIN
DECLARE _id INT;
START TRANSACTION;
INSERT INTO users (user_name, user_location) VALUES(_name, _location);
SET _id = LAST_INSERT_ID();
UPDATE users
SET encrypted_userid = AES_ENCRYPT(_id, 'MYAESKEY')
WHERE user_id = _id;
COMMIT;
END//
DELIMITER ;
Sample usage:
CALL insert_user('johndoe', null);
I solved my problem using MySQL - Trigger for updating same table after insert (JCLG's entry)
CREATE TRIGGER `useridinserttrigger` BEFORE INSERT ON `users`
FOR EACH ROW BEGIN
DECLARE tmpid,tmpid2 INT(11);
SELECT user_id INTO tmpid FROM users ORDER BY user_id DESC LIMIT 1;
SET tmpid2=tmpid+1;
SET new.encrypted_userid=AES_ENCRYPT(tmpid2,'MYAESKEY');
END;