Am trying to create a stored procedure that will notify me if a username or email already exists in the table.
Here is the structure of my table
CREATE TABLE IF NOT EXISTS `user` (
`user_id` smallint(5) unsigned NOT NULL,
`username` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`email` varchar(60) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`password` varchar(128) NOT NULL,
`active` tinyint(4) NOT NULL DEFAULT '1',
`date_joined` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`user_category_id` tinyint(3) unsigned NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
and here is the code for the stored procedure
DELIMITER $$
CREATE PROCEDURE `sp_create_account`( username_param VARCHAR(40), email_param VARCHAR(60), pass VARCHAR(30), category_id TINYINT )
BEGIN
DECLARE salt VARCHAR(60);
DECLARE username_var VARCHAR(40);
DECLARE email_var VARCHAR(60);
SELECT username_var INTO username_var FROM user WHERE username = username_param;
SELECT email_var INTO email_var FROM user WHERE email = email_param;
IF username_var = username_param THEN
SELECT 'username' AS message;
ELSEIF email_var = email_param THEN
SELECT 'email' AS message;
ELSE
SET salt = '#4$^7EC%?';
SET salt = CONCAT( username_param, salt );
INSERT INTO user VALUES
( DEFAULT, username_param, email_param, AES_ENCRYPT( pass, salt ), DEFAULT, DEFAULT, category_id );
SELECT 'created' AS message;
END IF;
END$$
DELIMITER ;
Two problems:
Problem 1:
Everything works fine when inserting an unique entry in which has the username or email does not exist, but when the username or email does exist i get these errors in the screenshot below yet i expect the stored procedure to return a simple select indicating where the problem could be or indicated success as the in case when it returns 'created'
Problem 2
If it is a unique entry and it gets inserted into the table, the password column cell in that particular row gets inserted with an empty string.
What could be the cause of all the above? Thanks you.
Perhaps these changes are what you are looking for. Changes to the schema, and your if blocks, and return values.
The return value is the AUTO_INCREMENT of the user id. Note, I pretty much followed your schema. Your Primary Key in that table could probably be collapsed a bit. Some might go lean with no user id or user name, but just the email address as the PK. Those are things to think about. I also added a unique key for email address.
Schema:
CREATE TABLE IF NOT EXISTS `user` (
`user_id` int auto_increment primary key,
`username` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`email` varchar(60) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`password` varbinary(128) NOT NULL,
`active` tinyint(4) NOT NULL DEFAULT '1',
`date_joined` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`user_category_id` tinyint(3) unsigned NOT NULL,
unique key (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- truncate table user;
Stored Procedure:
drop procedure if exists sp_create_account;
DELIMITER $$
CREATE PROCEDURE `sp_create_account`
( username_param VARCHAR(40),
email_param VARCHAR(60),
pass VARCHAR(30),
category_id TINYINT
)
BEGIN
DECLARE salt VARCHAR(60);
DECLARE username_var VARCHAR(40);
DECLARE email_var VARCHAR(60);
DECLARE recFound int;
DECLARE foundStatus int DEFAULT 0;
SELECT user_id INTO recFound FROM user WHERE username = username_param;
IF recFound is null THEN
SELECT user_id INTO recFound FROM user WHERE email = email_param;
IF recFound is not null THEN
SET foundStatus=1;
END IF;
ELSE
SET foundStatus=1;
END IF;
IF foundStatus=0 THEN
SET salt = '#4$^7EC%?';
SET salt = CONCAT( username_param, salt );
INSERT INTO user (username,email,password,active,date_joined,user_category_id) VALUES
( username_param, email_param, AES_ENCRYPT( pass, salt ), DEFAULT, DEFAULT, category_id );
set recFound=LAST_INSERT_ID();
END IF;
SELECT recFound;
END$$
DELIMITER ;
Test:
call sp_create_account('Katherine','ksmith#hotmail.com','thepass01',101);
call sp_create_account('Katherine','ksmith#hotmail.com','thepass01',101);
call sp_create_account('Katherine','ksmith#hotmail.com','thepass01',101);
call sp_create_account('caspar','caspar001#gmail.com','thepass02',77);
select * from user;
+---------+-----------+---------------------+------------------+--------+---------------------+------------------+
| user_id | username | email | password | active | date_joined | user_category_id |
+---------+-----------+---------------------+------------------+--------+---------------------+------------------+
| 1 | Katherine | ksmith#hotmail.com | _╦*Fó▄GàB╔┌O►²§' | 1 | 2016-07-13 17:56:54 | 101 |
| 2 | caspar | caspar001#gmail.com | ♀½B§5U├↨I♀#*├ ∟L | 1 | 2016-07-13 17:57:09 | 77 |
+---------+-----------+---------------------+------------------+--------+---------------------+------------------+
2 rows in set (0.00 sec)
Your last ELSE needs to have all the commands you expect to execute in it enclosed in BEGIN ... END. Maybe? I've been working more in MSSQL lately.
Related
This is an example as I do not want to display my real table.I have 4 columns for a table test in mysql (phpmyadmin).
CREATE TABLE `test` (
`c1` int(11) NOT NULL,
`c2` date DEFAULT NULL,
`c3` varchar(35) DEFAULT NULL,
`c4` int(11) DEFAULT NULL
) ;
and a stored procedure to insert only three columns which is not working.
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `testing`(IN `_c1` INT, IN `_c2` DATE, IN `_c3` VARCHAR(35))
NO SQL
BEGIN
INSERT INTO `test`(`c1`,`c2`,`c3`) values(_c1,_c2,_c3);
END$$
DELIMITER ;
There is no error in creating the SP, or executing it. If I change the store procedure to insert all the four columns c1,c2,c3 and c4, it works fine, for which all the parameters are given correctly as per the datatype I have specified. Note that I have specified the default value as NULL for the columns which would not be mandatory to be inserted every time.
Your code works in mysql , try from command line to see if this is a phpmyadmin issue.
CREATE TABLE `t` (
`c1` int(11) NOT NULL,
`c2` date DEFAULT NULL,
`c3` varchar(35) DEFAULT NULL,
`c4` int(11) DEFAULT NULL
) ;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `testing`(IN `_c1` INT, IN `_c2` DATE, IN `_c3` VARCHAR(35))
NO SQL
BEGIN
INSERT INTO `t`(`c1`,`c2`,`c3`) values(_c1,_c2,_c3);
END$$
DELIMITER ;
call testing(10,'2017-11-01','aaa');
select * from t;
+----+------------+------+------+
| c1 | c2 | c3 | c4 |
+----+------------+------+------+
| 10 | 2017-11-01 | aaa | NULL |
+----+------------+------+------+
1 row in set (0.00 sec)
I have this tables
CREATE TABLE `autores` (
`id_autor` int(11) NOT NULL DEFAULT '0',
`login` varchar(60) NOT NULL DEFAULT '',
`password` varchar(64) NOT NULL DEFAULT '',
`correo` varchar(100) NOT NULL DEFAULT '',
`url` varchar(100) NOT NULL DEFAULT '');
CREATE TABLE `noticias` (
`id` int(11) NOT NULL DEFAULT '0',
`autor_id` char(15) NOT NULL DEFAULT '0',
`fecha_pub` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`contenido` longtext NOT NULL,
`titulo` text NOT NULL,
UNIQUE KEY `in1` (`id`),
FULLTEXT KEY `full` (`titulo`,`contenido`)
) ENGINE=MyISAM AUTO_INCREMENT=3844 DEFAULT CHARSET=latin1;
Now i've created a procedure that calculates who's the author that has the most "articles" published.
create procedure masnoticiasmes(in mes int)
begin
declare empate int default 0;
declare nombreautor VARCHAR(30);
declare cantidad, autor, autormax int;
declare maximo, fin int default 0;
declare nombreautor2,nombreempate char(30);
declare empatado char(30);
declare micursor cursor for select count(id), autor_id from noticias where month(fecha_pub)=mes group by autor_id;
declare continue handler for not found set fin=1;
open micursor;
repeat
fetch micursor into cantidad, autor;
if fin=0 then
if cantidad>maximo then
set maximo=cantidad;
set autormax=autor;
set empate=0;
end if;
if cantidad=maximo and autormax != autor then
set empatado=autor;
set empate=empate+1;
end if;
end if;
until fin end repeat;
select login from autores join noticias on noticias.autor_id=autores.id_autor where cantidad IN (maximo) into nombreempate;
close micursor;
select login from autores join noticias on noticias.autor_id=autores.id_autor where autores.id_autor=empatado into nombreempate;
select concat ( "El que mas ha publicado es el: ", nombreautor2," con ", maximo, " noticias ", " empatados ", empate,nombreempate) as "resultado";
end//
Now my problem is that when a tie happens , i have to say
the most published author is X (because of the way cursor works it picks up the first most published even if there's a tie) then it says there are X ties
and the author that has a tie is X , the problem is that the most published author is a variable , and when there's a tie between 2 it works fine , just selecting from the table the name of the author where the id is the author id.
But if there are more than 2 authors , i would have to store the name in a variable , 1 variable for every author that ties is just not doable , how would you do it?
I have a stored procedure, that checks if there is a user with the same e-mail address as the input, if not, then registeres one.
Here is the table:
CREATE TABLE IF NOT EXISTS `overkill`.`accounts` (
`accountID` INT NOT NULL AUTO_INCREMENT ,
`email` VARCHAR(64) NOT NULL ,
`firstName` VARCHAR(32) NOT NULL ,
`lastName` VARCHAR(32) NOT NULL ,
`passSaltedSHA` BINARY(20) NOT NULL ,
`salt` BINARY(20) NOT NULL ,
`gender` ENUM('m','f') NOT NULL ,
`birthDate` DATE NOT NULL ,
`regTime` TIMESTAMP NOT NULL ,
PRIMARY KEY (`accountID`) )
ENGINE = InnoDB;
Here is the stored procedure:
DELIMITER $$
CREATE PROCEDURE `overkill`.`registerUser` (
IN emailIN VARCHAR(64),
IN passwordIN VARCHAR(16),
IN firstNameIN VARCHAR(32),
IN lastNameIn VARCHAR(32),
IN birthIN DATE,
IN genderIN ENUM('f','m'))
BEGIN
DECLARE existingMailAccLOG INT DEFAULT NULL;
DECLARE saltLOC CHAR(40);
DECLARE regSuccessLOC BOOLEAN DEFAULT FALSE;
SELECT COUNT(*) INTO existingMailAccLOG FROM `overkill`.`accounts` WHERE `accounts`.`email` = emailIN;
IF existingMailAccLOG = 0 THEN
SET saltLOC = SHA1(rand());
SET regSuccessLOC = TRUE;
INSERT INTO `overkill`.`accounts` (`email`, `firstName`, `lastName`, `passSaltedSHA`, `salt`, `gender`, `birthDate`) VALUES(emailIN, firstNameIN, lastNameIn, UNHEX(SHA1(CONCAT(passwordIN, saltLOC))), UNHEX(saltLOC), genderIN, birthIN);
END IF;
SELECT regSuccessLOC AS `registered`, saltLOC AS `salt`;
END
If I call:
CALL registerUser("abc#def.com", "pass", "firstn", "lastn", "2012-01-01", "f");
It inserts a line into the accounts table, but forgets to return the proper values that I set inside the IF
SET saltLOC = SHA1(rand());
SET regSuccessLOC = TRUE;
How is it even possible? Why are theese lines skipped and INSERT still gets executed, without mistake?
Try to add "#" in front of your variable names after DECLARE keyword. It can cause some confusion, as it is described here: MySQL: #variable vs. variable. Whats the difference? (Part2) and here: MySQL: #variable vs. variable. Whats the difference?
Within a BPM web application, I have a field for an invoice # on a particular page but I need for it to be auto generated every time a user attaches an invoice and views that page. That number must be unique and preferably auto-incremented. A value for the invoice # field can be displayed by querying from a table from an external MYSQL database. So every time a user lands on that particular page, a SELECT query statement can be fired.
On MYSQL end, how would I set this up? So basically, I would like to setup a query for that invoice # field where it will for run a query for example,
SELECT invoice_num FROM invoice_generator
and every time this query runs, it would return the next incremented number.
You can use mysql trigger concept here....
I have added one example here...
It will be very usefull for u (see this link also :http://www.freemindsystems.com/mysql-triggers-a-practical-example/)
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT '',
`price` int(20) NOT NULL DEFAULT '0',
`other` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `products_name_idx` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `freetags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag` varchar(50) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `freetagged_objects` (
`tag_id` int(20) NOT NULL DEFAULT '0',
`object_id` int(20) NOT NULL DEFAULT '0',
`tagged_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`module` varchar(50) NOT NULL DEFAULT '',
PRIMARY KEY (`tag_id`, `object_id`),
KEY `freetagged_objects_tag_id_object_id_idx` (`tag_id`, `object_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
INSERT_PRODUCTS_TAGS
DELIMITER ||
DROP TRIGGER IF EXISTS insert_products_tags;
||
DELIMITER ##
CREATE TRIGGER insert_products_tags AFTER INSERT ON products
FOR EACH ROW
BEGIN
DECLARE current_id integer;
DECLARE tag_id integer;
DECLARE next integer;
DECLARE tag_field varchar(255);
DECLARE next_sep integer;
DECLARE current_tag varchar(255);
DECLARE right_tag varchar(255);
-- We use the field other as comma-separated tag_field
SET tag_field = NEW.other;
-- Check for empty tags
IF (CHAR_LENGTH(tag_field) <> 0) THEN
-- Loop until no more ocurrencies
set next = 1;
WHILE next = 1 DO
-- Find possition of the next ","
SELECT INSTR(tag_field, ',') INTO next_sep;
IF (next_sep > 0) THEN
SELECT SUBSTR(tag_field, 1, next_sep - 1) INTO current_tag;
SELECT SUBSTR(tag_field, next_sep + 1, CHAR_LENGTH(tag_field)) INTO right_tag;
set tag_field = right_tag;
ELSE
set next = 0;
set current_tag = tag_field;
END IF;
-- Drop spaces between comas
SELECT TRIM(current_tag) INTO current_tag;
-- Insert the tag if not already present
IF (NOT EXISTS (SELECT tag FROM freetags WHERE tag = current_tag)) THEN
-- Insert the tag
INSERT INTO freetags (tag) values (current_tag);
SELECT LAST_INSERT_ID() INTO tag_id;
ELSE
-- Or get the id
SELECT id FROM freetags WHERE tag = current_tag INTO tag_id;
END IF;
-- Link the object tagged with the tag
INSERT INTO freetagged_objects
(tag_id, object_id, module)
values
(tag_id, NEW.id, 'products');
END WHILE;
END IF;
END;
##
Now If you execute an insert on products table:
INSERT INTO PRODUCTS
(name, price, other)
values
("product1", 2, "tag1, tag2,tag3 , tag 4");
I have a user Form where users Fill in the following details
a) Username b) Password c) Email
Username and Password belongs to users table whereas Email belongs to contacts table , now users table have foreign key contact_id which stores the Primary Key id of contacts. whenever the user submit the form i have to make two MySQL Queries to insert records into two different table.
Here is what i am using.
First Query:
$sth = $this->dbh->prepare("INSERT INTO contacts(email) VALUES(:email)");
Second Query :
$sth = $this->dbh->prepare("INSERT INTO users(username,password,registerdate,activationString,contact_id) VALUES(:username,:password,NOW(),:activationString,".$this->dbh->lastInsertId().")");
is there anyway i could make the query into one instead of two? utilizing MySQL last_insert_id() function. ?
thank you
INSERT statement allows to insert into one table.
But you could create a stored procedure to do the job.
Example:
CREATE TABLE contacts(
id INT(11) NOT NULL AUTO_INCREMENT,
email VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id)
);
CREATE TABLE users(
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(255) DEFAULT NULL,
`password` VARCHAR(255) DEFAULT NULL,
registerdate DATE DEFAULT NULL,
activationString VARCHAR(255) DEFAULT NULL,
contact_id VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id)
);
DELIMITER $$
CREATE
PROCEDURE add_new_user(IN p_username VARCHAR(255),
IN p_password VARCHAR(255),
IN p_registerdate DATE,
IN p_activationString VARCHAR(255),
IN p_email VARCHAR(255)
)
BEGIN
INSERT INTO contacts (email) VALUES (p_email);
INSERT INTO users (username, password, registerdate, activationString, contact_id) VALUES (p_username, p_password, p_registerdate, p_activationString, LAST_INSERT_ID ());
END
$$
DELIMITER ;
SET #p_username = 'user1';
SET #p_password = 'pwd';
SET #p_registerdate = now();
SET #p_activationString = 'str';
SET #p_email = 'addr#host.net';
CALL database3.add_new_user(#p_username, #p_password, #p_registerdate, #p_activationString, #p_email);
Stored procedure is optional, you can use two insert statements.