SQL max number of records - mysql

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

Allow only unique combination of values for a composite primary key

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.

insert, if exist update using trigger

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

fetching a records from binary tree in mysql

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

MySql if else statement, if not valid in this position

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

mysql trigger to update one field of the newly added row

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;