MySQL insert unique record by index of columns - mysql

I have a table:
table user(
id_user,
userName,
email,
primary key(id_user)
);
I added unique index on it:
alter table user add unique index(userName, email);
Now I have two indexs on the table:
Index:
Keyname Unique Field
PRIMARY Yes id_user
userName Yes userName, email
The task is to find the MySQL statement for fastest way to insert new unique record.
Statement should return Id_user of the new or existent record.
I'm considering these 2 options, and don't know which is better or is there some third better way to do this?:
1.
INSERT INTO `user` (`userName`, `email`)
VALUES (u1,'u1#email.me' )
ON DUPLICATE KEY Ignore
Q: Where in this statement should be specified that the required KEY for unique inserts is Keyname = uesrName?
2.
IF EXISTS(SELECT `userName`, `email` FROM user WHERE `userName` = u1 AND `email` = u1#email.me)
BEGIN
END
ELSE
BEGIN
INSERT INTO user(`userName`, `email`)
VALUES (u1, u1#email.me);
END IF;
Q: In this statement - how the index with Keyname = userName should be taken in consideration?
Thanks!

The only way to get data out of a table in MySQL is to select.
DELIMITER $$
CREATE FUNCTION ForceUser(pUsername varchar(255), pEmail varchar(255))
RETURNS integer
BEGIN
DECLARE MyId INTEGER;
/*First do a select to see if record exists:*/
/*because (username,email) is a unique key this will return null or a unique id.*/
SELECT id INTO MyId FROM user
WHERE username = pUsername
AND email = pEmail;
IF MyId IS NULL THEN
/*If not then insert the record*/
INSERT INTO user (username, email) VALUES (pUserName,pEmail);
SELECT LAST_INSERT_ID() INTO MyId;
END IF;
RETURN MyID;
END $$
DELIMITER ;
Q: Where in this statement should be specified that the required KEY for unique inserts is Keyname = uesrName?
A: MySQL already knows this, because that information is part of the table definition.
See: http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html

Related

MySQL: insert procedure, with variable from another table

I have two tables:
CREATE TABLE userTypes (
id INTEGER NOT NULL PRIMARY KEY,
type VARCHAR(50) NOT NULL
);
CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(50) NOT NULL,
userTypeId INTEGER NOT NULL,
FOREIGN KEY (userTypeId) REFERENCES userTypes(id)
);
INSERT INTO userTypes (id, type) VALUES (0, 'free');
INSERT INTO userTypes (id, type) VALUES (1, 'paid');
I want to create a procedure where that it inserts a user in the users table, with :
id is auto incremented.
email is equal to the email parameter.
userTypeId is the id of the userTypes row whose type attribute is equal to the type parameter
The INSERT function doesn't work with WHERE, so I tried to add a UPDATE but it's not working. Here's what I have for the moment:
DELIMITER //
CREATE PROCEDURE insertUser(
IN type VARCHAR(50),
IN email VARCHAR(50)
)
BEGIN
INSERT INTO users(id, email, userTypeID) VALUES (LAST_INSERT_ID(), email, userTypeID);
UPDATE users SET users.userTypeID = usertypes.id
WHERE usertypes.type = type;
END//
DELIMITER ;
The expected result should be something like this:
CALL insertUser('free', 'name_1#mail.com');
CALL insertUser('paid', 'name_2#mail.com');
SELECT * FROM users;
id email userTypeId
------------------------------------------
1 name_1#mail.com 0
2 name_2#mail.com 1
Leave out the auto_increment-column. As the name suggests, the db will fill this automatically.
Then, use different names for the parameters than the column names. You can use a prefix with the parameters.
Additionally, you could consider using the userTypeId integer value as parameter instead of the textual value. Otherwise you need to handle the situation where the passed type is not among the types in the userTypes (create a new one/reject insert).
DELIMITER //
CREATE PROCEDURE insertUser(
in_type VARCHAR(50),
in_email VARCHAR(50)
)
BEGIN
INSERT INTO users(email, userTypeID)
SELECT in_email, id
FROM userTypes
WHERE type=in_type;
IF (ROW_COUNT()=0) THEN
SELECT 'Error';
ELSE
SELECT 'OK';
END IF;
END//
DELIMITER ;

SQL max number of records

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.

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;

MySQL Stored Procedure, Insert if row doesn't exist. Select id of that row (either inserted row or pre-existing row)

I am creating a stored procedure to register a user.
Here is the create:
CREATE TABLE User (
UID INT AUTO_INCREMENT,
Fname VARCHAR(32) NOT NULL,
Lname VARCHAR(32) NOT NULL,
Phone VARCHAR(32),
Email VARCHAR(50),
Pass VARCHAR(32),
CONSTRAINT User_PK PRIMARY KEY(EmpID),
CONSTRAINT User_UK1 UNIQUE (FName, LName, Phone),
CONSTRAINT User_UK2 UNIQUE (FName, LName, Email),
CONSTRAINT User_UK3 UNIQUE (Email, Pass)
)ENGINE=InnoDB;
Here is the stored procedure so far:
DELIMITER //
CREATE PROCEDURE regUser(fname VARCHAR(32),lname VARCHAR(32),phone VARCHAR(32), email VARCHAR(50), pass VARCHAR(32))
BEGIN
DECLARE uid INT;
DECLARE CONTINUE HANDLER FOR 1062 BEGIN END;
START TRANSACTION;
INSERT INTO User(Fname, Lname, Phone, Email, Pass) VALUES(fname, lname, phone, email, pass);
SELECT UID FROM User WHERE Phone=phone OR Email=email AND Fname=fname AND Lname=lname;
COMMIT;
END //
DELIMITER ;
In the stored procedure it attempts the insert, if a duplicate entry is found the continue handler(1062) catches the error and doesn't do anything. After the insert (or lack of) I want to select the UID of the inserted row, or of the pre-existing row (if no insert was done due to duplicate)
What is happening: The SELECT UID..WHERE... is returning a column of 4 NULL values instead of the UID of the row WHERE Phone=phone OR Email=email AND Fname=fname AND Lname=lname;
I believe the 4 NULL values are because I have 4 Users in the User table at the moment.
I am completely puzzled on this, if I do the SELECT UID..WHERE... outside of the stored procedure, it works just fine, returning the UID WHERE Phone=phone...
I get the same result NULL when inserting a User that is already in the table and when trying a new unique user.