I am trying to make a stored procedure in MySQL that will take the highest number from a column, add one and use it to make the next entry.
DROP PROCEDURE IF EXISTS ops_software.create_invoice;
DELIMITER //
CREATE PROCEDURE ops_software.create_invoice(IN company VARCHAR(50))
BEGIN
SELECT #old_invoice_number := MAX(invoice_number)
FROM invoices
WHERE invoices.company = company;
SET #new_invoice_number := #old_invoice_number + 1
INSERT INTO invoices (company, invoice_number)
VALUES (company, #new_invoice_number)
END//
DELIMITER ;
CALL ops_software.create_invoice('Super Company')
I don't want to use the auto-increment feature because there are several different company names and each has their own invoice numbers
Getting the value works, but I can't add one to it or insert it to make a new entry
Thanks
CREATE PROCEDURE ops_software.create_invoice(IN in_company VARCHAR(50))
INSERT INTO invoices (company, invoice_number)
SELECT in_company, MAX(invoices.invoice_number) + 1
FROM invoices
WHERE invoices.company = in_company;
DELIMITER and BEGIN-END not needed.
PS. May produce duplicates in concurrent environment.
Related
What is the error in the following code. I am executing in mysql
CREATE TRIGGER tg_order_insert
BEFORE INSERT
ON `order` FOR EACH ROW
BEGIN
INSERT INTO `grocery`.`order_seqid` VALUE(NULL);
SET NEW.order_id = CONCAT('#GNC', LPAD(LAST_INSERT_ID(),3,'0'));
END;
Grocery is the database and order_seqid and order are 2 table.
order_seqid is a table with only 1 attribute if type int and auto increment.
Am trying to put a prefix on the id which we insert into order table.
I am getting 2 errors in INSERT INTO..... and END; line
Did you declare a delimiter before your trigger definition? Something like
DELIMITER //
CREATE TRIGGER tg_order_insert
BEFORE INSERT
ON `order` FOR EACH ROW
BEGIN
INSERT INTO `grocery`.`order_seqid` VALUE(NULL);
SET NEW.order_id = CONCAT('#GNC', LPAD(LAST_INSERT_ID(),3,'0'));
END
//
Because if you don't, then MySQL thinks you're trying to end your trigger definition when it sees that first ; and calls syntax error.
I wrote store procedure in mysql. Step were followed this website http://www.mysqltutorial.org/mysql-cursor/
But it doesn't work. Here is code
DELIMITER $$
USE `hr`$$
DROP PROCEDURE IF EXISTS `at_getShift`$$
CREATE DEFINER=`root`#`%` PROCEDURE `at_getShift`()
BEGIN
DECLARE finished BOOLEAN DEFAULT FALSE;
DECLARE employeeID VARCHAR(255);-- Default "";
-- declare cursor for employee email
DECLARE hrEmployee CURSOR FOR SELECT EmployeeID FROM h_employees WHERE EmployeeID IN ('100013', '100014');
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = TRUE;
DROP TABLE IF EXISTS temp;
CREATE TABLE IF NOT EXISTS temp(
`Code` VARCHAR(255)
);
OPEN hrEmployee;
get_employee: LOOP
FETCH hrEmployee INTO employeeID;
INSERT INTO temp(`Code`) VALUE (employeeID);
-- If no any row, leave loop
IF finished THEN
INSERT INTO temp(`Code`) VALUE ("112");
CLOSE hrEmployee;
LEAVE get_employee;
END IF;
-- insert temp
INSERT INTO temp(`Code`) VALUE ("111");
END LOOP get_employee;
SELECT * FROM temp;
END$$
DELIMITER ;
Execute: CALL at_getShift();
Result is:
2 rows in temp table ( 1 null, 1 is 112)
Please kindly help me to resolve this trouble.
In a SQL statement in MySQL stored program, the references to procedure variables take precedence over references to columns.
That is, when an identifier in a SQL statement matches a procedure variable, the SQL statement references the procedure variable.
References that are qualified with the table name or table alias reference columns from the table, even when there is a procedure variable with the same name.
Demonstration:
CREATE TABLE emp (id INT);
INSERT INTO emp (id) VALUES (101),(102);
DELIMITER $$
CREATE PROCEDURE foo()
BEGIN
DECLARE id INT DEFAULT 3;
-- this query returns 3 for all rows in emp
-- because "id" is a reference to the procedure variable
SELECT id FROM emp WHERE id = 3;
-- this query returns no rows
-- because "id" is a reference to the procedure variable
SELECT id FROM emp WHERE id = 101;
-- this query references columns in the table because
-- references to "id" are qualified
SELECT t.id FROM emp t WHERE t.id = 101;
END$$
DELIMITER ;
CALL foo;
The first query returns value of procedure variable for all rows from emp
id
-----
3
3
second query returns no rows
id
-----
third query returns references "id" column in table:
id
-----
101
The takeaway are two "best practices":
qualify all column references in a SQL statement in a procedure
and
procedure variable names should differ from names of columns, the usual pattern is to use a distinctive prefix on variables. As a trivial example: v_id, v_name, etc.
Both of these practices make it easier for a human reader to decipher a procedure.
Distinctive naming of procedure variables does reduce the chances of collisions, but does not invalidate the "best practice" of qualifying all column references in SQL statements. Both of those serve to make the author's intent more clear to the human reader.
EDIT:
I attempted to answer the question I thought you were asking... "Why is my procedure not doing what I expect it to?".
Beyond the answer to the question you asked... the operation that your procedure appears to be performing (populating a temporary table with a set of rows) that operation could be performed much faster and more efficiently by processing the rows as a set, rather than issuing painfully inefficient individual insert statements for each row. In terms of performance, a cursor loop processing RBAR (row-by-agonizing-row) is going to eat your lunch. And your lunch box.
DELIMITER $$
CREATE PROCEDURE `at_getShift_faster`()
BEGIN
-- ignore warning message when dropping a table that does not exist
DECLARE CONTINUE HANDLER FOR 1305 BEGIN END;
DROP TABLE IF EXISTS temp;
CREATE TABLE IF NOT EXISTS temp(`Code` VARCHAR(255));
INSERT INTO temp (`Code`)
SELECT h.EmployeeID
FROM h_employees h
WHERE h.EmployeeID IN ('100013', '100014')
;
SELECT * FROM temp;
END$$
DELIMITER ;
I have two tables which I use to store call details in. One table (Call_Detail) stores the header details against each call that gets entered, the second (Call_History) stores every comment against the call. So a single call will only appear ONCE in the Call_Detail table, but may appear multiple times in the Call_History table.
I currently run a Query to return the latest comment against a group of calls. So, I return the header details out of Call_Detail and then cross reference against the Call_History to find the 'newest' comment (thanks to some outside help). However, this Query can be quite time consuming when running against a large number of calls.
Therefore, I'm thinking to optimize my Query, I want to setup a trigger that records these details.
I am wanting to catch any INSERT command into the Call_History table and record the comment and date/time into the Call_Detail table against the relevant call ID.
So far I have the following but it doesn't like my syntax for some reason:
DELIMITER $$
CREATE TRIGGER Last_Call_Update
AFTER INSERT ON call_history
FOR EACH ROW
BEGIN
UPDATE call_detail
SET last_updated = NEW.updated_at, last_commment = NEW.body
WHERE id = NEW.ticket_id
END $$
DELIMITER ;
Add semicolon after UPDATE statement
DELIMITER $$
CREATE TRIGGER Last_Call_Update
AFTER INSERT ON call_history
FOR EACH ROW
BEGIN
UPDATE call_detail
SET last_updated = NEW.updated_at, last_commment = NEW.body
WHERE id = NEW.ticket_id;
END $$
DELIMITER ;
I'm trying to create a trigger, however I keep getting back a syntax error.
Here's the statement:
DELIMITER $$
CREATE TRIGGER `swtalentbank`.`after_candidate_insert`
AFTER INSERT ON `Candidates` FOR EACH ROW
BEGIN
INSERT INTO useradmin (username, talent)
VALUES (NEW.email, 1);
UPDATE `Candidates` SET UserID = useradmin.userid where useradmin.username = NEW.email;
END
DELIMITER ;
I have a registration form on my site. When a person registers it populates the Candidates table with their profile information.
In the Candidates table, there are various fields, two of them being 'email' and 'UserID'.
UserID is also the PK in 'useradmin', so I'm linking the two up.
So when a user registers, I need to insert a record into 'useradmin' with the email address that's just been used to register, and then update the 'Candidates' table, with UserID that's just been created in 'useradmin'.
I hope this makes sense?
NB. I am changing the delimiter before running the statement.
Besides properly using DELIMITER when creating a trigger you have at least two fundamental issues with your current code:
In MySQL you can't use issue a DML statement (in your case UPDATE) against a table (candidates) on which you defined a trigger (also candidates). Your only option is to use BEFORE trigger and set a value of userid column of a row being inserted to a proper value.
You can't arbitrarily reference a column (useradmin.userid) of a table out of the context like you did in your UPDATE. You didn't joined useradmin table or used it in a subquery.
That being said and assuming that userid in useradmin table is an auto_increment column your trigger might look like this
DELIMITER $$
CREATE TRIGGER after_candidate_insert
BEFORE INSERT ON candidates
FOR EACH ROW
BEGIN
INSERT INTO useradmin (`username`, `talent`) VALUES (NEW.email, 1);
SET NEW.userid = LAST_INSERT_ID();
END$$
DELIMITER ;
Here is SQLFiddle demo
You should use semicolon after end your insert query.
You can use INSERT ... ON DUPLICATE KEY UPDATE syntax for your purpose
try out this...
DELIMITER $$
CREATE TRIGGER `swtalentbank`.`after_candidate_insert`
AFTER INSERT ON `Candidates` FOR EACH ROW
BEGIN
INSERT INTO useradmin (username, talent)
VALUES (NEW.email, 1);
UPDATE `Candidates` SET UserID = useradmin.userid where useradmin.username = NEW.email;
END $$
DELIMITER ;
I Have a database called 'lms' with two tables loan and value, table loan has: loan_amount, yearly_intrest, loan type; table value has value_id,value_name, value_amount.
What i want is for my trigger to calculate the yearly interest in the loan table using the interest rate(value_amount) from the other table value where the loan_type(from loan table) is equal to the value (from Value table)
I tried this, it needs some help
-- Trigger DDL Statements
DELIMITER $$
USE `lms`$$
CREATE
DEFINER=`root`#`localhost`
TRIGGER `lms`.`updateloan`
BEFORE INSERT ON `lms`.`loan` INNER JOIN 'lms'.'value'
FOR EACH ROW
BEGIN
l.loan_type ="Computer Loan"
SET l.yearly_intrest = (l.loan_amount *(v.value_amount/100))
WHERE l.loan_type=v.value_name;
END$$
Table value contains two value_names Computer and Motor vehicle with value amounts of 2, 5
i hope my explanation is clear enough
I have not tried this but it should work -
DELIMITER $$
USE `lms`$$
CREATE
DEFINER=`root`#`localhost`
TRIGGER `lms`.`updateloan`
BEFORE INSERT ON `lms`.`loan`
FOR EACH ROW BEGIN
SET NEW.yearly_interest = (SELECT NEW.loan_amount * value_amount/100 FROM `lms`.`value` WHERE value_name = NEW.loan_type);
END$$