I created a function:
DELIMITER $$
DROP FUNCTION IF EXISTS `heena`.`customer_id`$$
CREATE DEFINER=`root`#`localhost` FUNCTION `heena`.`customer_id`(
a varchar(20),
b varchar(20)
) RETURNS varchar(50) CHARSET latin1
DETERMINISTIC
BEGIN
RETURN CONCAT(
(select ((id), 0) + 1
from heenaj),
substring(a,1,2),
substring(b,1,2));
END;$$
DELIMITER ;
The code executed fine, but when I'm inserting a value using:
insert into heenaj
(c_id,name,number)
values
(customer_id121("abcd",9868275817),"abcd",9868275817);
It shows an error:
Column 'c_id' cannot be null
There's something wrong with your RETURN.
Maybe you are meaning to do this, although I am only guessing:
RETURN CONCAT(
(select ifnull(max(id), 0) + 1
from heenaj),
substring(a,1,2),
substring(b,1,2));
sqlfiddle
Then, you're calling customerid121() not customer_id(). Could this be typo?
Also, in looking at what you're trying to do: do you want your id as auto_increment and just want to have c_id as the id, concatenated with first 2 characters of name and concatenated with first 2 characters of number?
I suggest another solution. It might be nicer to drop your function and create a TRIGGER for before INSERT, like this:
CREATE TRIGGER set_customer_id BEFORE INSERT on heenaj
FOR EACH ROW
BEGIN
SET NEW.c_id = CONCAT((SELECT IFNULL(MAX(id),0)+1 FROM heenaj),SUBSTRING(NEW.name,1,2),SUBSTRING(NEW.number,1,2));
END/
This way, when you insert you can just ignore c_id and insert like this:
insert into heenaj(name,number)
values ("abcd",9868);
The trigger will handle the setting of c_id for you.
sqlfiddle for TRIGGER
P.S. To create the trigger (in the sqlfiddle), I selected / as my delimiter. You might change that / to $$, since you're setting delimiter as $$.
Related
Why is the data not being inserted on the table when I execute the procedure, what seems to be lacking with the code?
I'm testing the procedure on phpMyAdmin > myDatabase > Procedures "Routines Tab" and clicking "Execute", prompts with a modal and ask for the values of "#idproc and #nameproc.
I tried with just the INSERT code it works, but when I add the IF condition it doesn't work.
Using XAMPP 8.0.3,
10.4.18-MariaDB
DELIMITER $$
CREATE DEFINER=`root`#`localhost:3307` PROCEDURE `testproc`(IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
IF #idproc = 0 THEN
INSERT INTO testproc(
id,
name)
VALUES(
#idproc,
#nameproc
);
ELSE
UPDATE testproc
SET
id = #idproc,
name = #nameproc
WHERE id = #idproc;
END IF;
SELECT * FROM testproc;
END$$
DELIMITER ;
You mix local variables (their names have not leading #) and user-defined variables (with single leading #). This is two different variable types, with different scopes and datatype rules. Procedure parameters are local variables too.
So when you use UDV which was not used previously you receive NULL as its value - and your code works incorrectly. Use LV everywhere:
CREATE DEFINER=`root`#`localhost:3307`
PROCEDURE `testproc` (IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
IF idproc = 0 THEN
INSERT INTO testproc (name) VALUES (nameproc);
ELSE
UPDATE testproc SET name = nameproc WHERE id = idproc;
END IF;
SELECT * FROM testproc;
END
You do not check does specified idproc value exists in the table. If it is specified (not zero) but not exists then your UPDATE won't update anything. Assuming that id is autoincremented primary key of the table I recommend to use
CREATE DEFINER=`root`#`localhost:3307`
PROCEDURE `testproc` (IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
INSERT INTO testproc (id, name)
VALUES (idproc, nameproc)
ON DUPLICATE KEY
UPDATE name = VALUES(name);
SELECT * FROM testproc;
END
If specified idproc value exists in id column the row will be updated, if not then the new row will be inserted.
Additionally - I recommend you to provide NULL value instead of zero when you want to insert new row with specified nameproc value. NULL always cause autoincremented primary key generation whereas zero needs in specific server option setting.
I'm in my first databases class and I'm trying to write a conditional block for a mysql procedure.
This is the procedure:
delimiter //
CREATE PROCEDURE add_ascent(IN cid INT, IN pid INT)
BEGIN
DECLARE count_ascents INT;
SET count_ascents = 0;
SELECT COUNT(`cid`) INTO count_ascents FROM ascents WHERE `cid`=cid AND `pid`=pid;
IF count_ascents < 1 THEN
INSERT INTO ascents (`cid`, `pid`) VALUES (cid, pid);
UPDATE climbers SET climbers.ascents = climbers.ascents + 1 WHERE climbers.id=cid;
UPDATE problems SET problems.ascents = problems.ascents + 1 WHERE problems.id=pid;
END IF;
END;
//
delimiter ;
The goal of the procedure is to only perform the insert and updates if the (cid, pid) pair is not in the the ascents database. After testing, the program doesn't seem to go into the if block at all.
FYI, you might want to consider using an UPSERT, instead of "select/if/insert". For example, mySQL offers INSERT ON DUPLICATE KEY UPDATE.
Here, I suggest:
giving your parameters a DIFFERENT name than the column name, for example iCid and iPid, then
Typing SELECT COUNT(cid) INTO count_ascents FROM ascents WHERE cid=iCid AND pid=iPid and checking the result.
I have created a mysql trigger to update on insert a value from another table:
DROP TRIGGER IF EXISTS `CourseCode`//
CREATE TRIGGER `CourseCode` BEFORE INSERT ON `race`
FOR EACH ROW BEGIN
SET NEW.Course_Code = (
SELECT
course_code
from
tb_course
where
tb_course.course_name = NEW.course_name
)
END
//
This works perfectly. It returns the 4 character code for the course_name based on the tb_course table.
What I'm trying to do is the exact same thing in another table, I copy and paste the trigger and rename the trigger and the table (field names and types are also identical) it but it won't work:
DROP TRIGGER IF EXISTS `CourseCode2`//
CREATE TRIGGER `CourseCode2` BEFORE INSERT ON `fields`
FOR EACH ROW
BEGIN
SET NEW.Course_Code = (
SELECT
course_code
from
tb_course
where
tb_course.course_name = NEW.course_name
)
END
//
However this results in null values. I've tried replacing New.Course_name with a string (i.e. tb_course.course_name="String") and that updates that static value fine so the trigger appears to be working but either it isn't matching the select statement in this table for or it's not setting the Course_Code field...
Is there any sort of debugging you can suggest to figure this out? It's driving me nuts and I don't know what to do to diagnose the problem.
Cheers
I have no idea what is wrong with the second trigger.
However, the 'debugging' part i can maybe help with.
A search of the 'net' will return various software (paid for) that will allow single step debugging. Rather than pay for stuff, all i want is 'print' statements from inside stored function procedures and triggers.
a quick search lead me to someone who has done all the work already.
Debugging Stored Procedures in MySql
I have just set it up in MySql and tried it and it works fine.
Here is some sample code, based on your trigger and the output i got.
DELIMITER $$
USE `testmysql`$$
DROP TRIGGER /*!50032 IF EXISTS */ `CourseCode`$$
CREATE
/*!50017 DEFINER = 'test'#'localhost' */
TRIGGER `CourseCode` BEFORE INSERT ON `race`
FOR EACH ROW BEGIN
DECLARE v_course_code INT;
DECLARE v_course_title VARCHAR(255);
CALL procLog("line 12: Entering CourseCode");
SELECT
course_code, course_title
INTO
v_course_code, v_course_title
FROM
tb_course
WHERE
tb_course.course_name = NEW.course_name;
SET NEW.course_code = v_course_code;
CALL procLog(CONCAT("line_22: ", v_course_title, " code: ", NEW.course_code));
CALL procLog("line 24: Exiting CourseCode");
END;
$$
DELIMITER ;
Query:
CALL setupProcLog();
INSERT INTO `race` (course_name, race_info)
VALUES ('learn_it_02', 'this is another test');
CALL cleanup('query end');
procLog output:
entrytime connection_id msg
2014-02-23 12:32:21 5 line 12: Entering CourseCode
2014-02-23 12:32:21 5 line_22: Learn It Course 02 code: 2
2014-02-23 12:32:21 5 line 24: Exiting CourseCode
2014-02-23 12:32:21 5 cleanup() query end
Ok, a little clumsy maybe but it will help with debugging 'stored' programs.
I will be using it from now on.
I have the following stored procedure:
DELIMITER //
CREATE PROCEDURE NewSeqType(IN mySubschemaID INT, IN hashVal bigint(20))
BEGIN
DECLARE newSeqTypeID INT;
SELECT MAX(ID)+1 INTO newSeqTypeID FROM sequenceType WHERE subschemaID=mySubschemaID;
INSERT INTO SequenceType(ID, HashValue, subschemaID) VALUES(newSeqTypeID, hashVal, mySubschemaID);
SELECT LAST_INSERT_ID() as ID; -- return prim key
END//
This works when there is already data in the table where subschemaID=mySubschemaID, but if that SELECT statement returns null, then the MAX(ID)+1 part gives the error column ID cannot be null.
How can I give ID a default value, say 0, in that case?
For this, you can use coalesce():
SELECT coalesce(MAX(ID)+1, 1) INTO newSeqTypeID FROM sequenceType WHERE subschemaID=mySubschemaID;
INSERT INTO SequenceType(ID, HashValue, subschemaID) VALUES(newSeqTypeID, hashVal, mySubschemaID);
Often, this type of work is done in a before insert trigger, to keep the values aligned.
I am trying to understand why this trigger keeps giving me an error about invalid use of grouped function when i try to run a basin insert statement to test this out.
I have tried working with this to figure out what i am doing wrong but the error just remains the same. Error 1111
DROP TRIGGER a_num;
DELIMITER //
CREATE TRIGGER a_num BEFORE INSERT ON test_a
FOR EACH ROW BEGIN
DECLARE last INT DEFAULT 0;
INSERT INTO test_b SET full_name = CONCAT_WS(' ', NEW.f_name, NEW.l_name);
SET last = COUNT(id);
UPDATE test_b SET number = CONCAT_WS('-', last, LEFT(NEW.f_name, 2), LEFT(NEW.f_name, 2)) WHERE id = last;
END;
//
Please don't mind the use or poor construction I quite a newb.
Thanks.
I think it should be -
DROP TRIGGER a_num;
DELIMITER //
CREATE TRIGGER a_num BEFORE INSERT ON test_a
FOR EACH ROW BEGIN
DECLARE last INT DEFAULT 0;
INSERT INTO test_b SET full_name = CONCAT_WS(' ', NEW.f_name, NEW.l_name);
SET last = LAST_INSERT_ID();
UPDATE test_b SET number = CONCAT_WS('-', last, LEFT(NEW.f_name, 2), LEFT(NEW.f_name, 2)) WHERE id = last;
END;
//
Can you provide the CREATE statement for test_a and the INSERT statement you're using?
In MySQL Workbench if you right click on test_a go to Copy to Clipboard..Create Statement, will send the table definition.
Is there a reason you're inserting and then updating the same record? Could you combine this into one insert?