I would like to create a table with an incremental counter, let's say from 14 to 17. The table should look like:
counter
14
15
16
17
Obviously, the range I really need is much larger. Any idea? I use MySQL.
Use the following stored procedure.
(change t1 to your table name)
DELIMITER $$
CREATE DEFINER=`server`#`%` PROCEDURE `test1`(start_num INT, end_num INT)
BEGIN
WHILE start_num < end_num DO
INSERT INTO t1 VALUES(start_num);
SET start_num = start_num + 1;
END WHILE;
END$$
Create an auto_increment column. See http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
Related
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.
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 an application that save data into a table , say my_table.
my_table
id | name | salary
this is a data entry application and not having a centralized database.Once all data entries complete, I have to merge the databases. My plan is to export insert statements from say DB2 and append it to DB1. So i wrote a procedure as follows:
CREATE PROCEDURE insertToTable
DECLARE max_id INT DEFAULT 1
BEGIN
SELECT MAX(id) INTO max_id FROM my_table
INSERT INTO table(id,name,salary) VALUES(max_id+1,'tom',1000);
INSERT INTO table(id,name,salary) VALUES(max_id+1,'john',1500);
....//a lot of statements
END
here i just increment id of DB2 by the max(id) of DB1 to avoid conflict.It works fine.
But some databases have large number of records.I could get these insert statements with 'max_id' variable in position.Then can I execute these 'insert' statements from file inside that procedure. Or is there any better solution..
Make "Id" column auto incremental by adding sequence.
Then create a trigger that increment upon insert.
I think i need this trigger:
CREATE TRIGGER insert_test BEFORE INSERT ON table my_table
FOR EACH ROW
BEGIN
SET #max_id = select max(id) from my_table;
IF NEW.id >= #max_id THEN
NEW.id = #max_id + 1;
END IF;
END;
Thanks for your suggestion.
I am working on a project where I need my ID column to be a power of 2 (1,2,4,8,16..). I know that we cannot offset the auto_increment but for simple addition/subtraction in my.cnf.
Example:
id
----
1
2
4
8
16
32
64
128
etc
One of the ideas I had was to use the auto increment functionality as the base, and then create a trigger to apply the power of 2 and update the new ID, but unfortunately, it is not working:
DELIMITER $$
CREATE TRIGGER testbitcompatid BEFORE INSERT ON Table
FOR EACH ROW
BEGIN
SET NEW.id = pow(NEW.id, 2)
END;
$$
DELIMITER ;
Because the BEFORE INSERT has not yet generated the AUTO_INCREMENT id, the AUTO_INCREMENT will always return 0, essentially causing no change on the columns.
I also tried AFTER INSERT:
DELIMITER $$
CREATE TRIGGER testbitcompatid AFTER INSERT ON Table
FOR EACH ROW
BEGIN
SET Table.id = pow(NEW.id, 2) WHERE id = NEW.id;
END;
$$
DELIMITER ;
But this failed because you cannot change values of the table which the trigger is applied to during an AFTER INSERT.
Scratching my head, but I am sure someone else has a great way of accomplishing this.
To work around all the issues above, I was able to construct the following which works great!
DELIMITER $$
CREATE TRIGGER testbitcompatid BEFORE INSERT ON Table
FOR EACH ROW
BEGIN
SET #LAST_ROW = (SELECT MAX(id) FROM Table);
SET NEW.id = CASE WHEN #LAST_ROW IS NULL THEN 1 ELSE #LAST_ROW * 2 END;
END;
$$
DELIMITER ;
Pretty much, we take the highest id, grab the log(2) of it which gives us the corresponding AUTO_INCREMENT id. We then add 1, and power that up to 2.
I hope this helps prevent some headache down the road for others.
The following procedure gives me an error when I invoke it using the CALL statement:
CREATE DEFINER=`user`#`localhost` PROCEDURE `emp_performance`(id VARCHAR(10))
BEGIN
DROP TEMPORARY TABLE IF EXISTS performance;
CREATE TEMPORARY TABLE performance AS
SELECT time_in, time_out, day FROM attendance WHERE employee_id = id;
END
The error says "Unknown table 'performance' ".
This is my first time actually using stored procedures and I got my sources from Google. I just cant figure out what I am doing wrong.
I've tidied it up a little for you and added example code. I always keep my parameter names the same as the fields they represent but prefix with p_ which prevents issues. I do the same with variables declared in the sproc body but prefix with v_.
You can find another one of my examples here:
Generating Depth based tree from Hierarchical Data in MySQL (no CTEs)
drop procedure if exists emp_performance;
delimiter #
create procedure emp_performance
(
in p_employee_id varchar(10)
)
begin
declare v_counter int unsigned default 0;
create temporary table tmp engine=memory select time_in, time_out
from attendance where employee_id = p_employee_id;
-- do stuff with tmp...
select count(*) into v_counter from tmp;
-- output and cleanup
select * from tmp order by time_in;
drop temporary table if exists tmp;
end#
delimiter ;
call emp_performance('E123456789');
By default MySQL config variable sql_notes is set to 1.
That means that
DROP TEMPORARY TABLE IF EXISTS performance;
increments warning_count by one and you get a warning when a stored procedure finishes.
You can set sql_notes variable to 0 in my.cnf or rewrite stored procedure like that:
CREATE DEFINER=`user`#`localhost` PROCEDURE `emp_performance`(id VARCHAR(10))
BEGIN
SET ##session.sql_notes = 0;
DROP TEMPORARY TABLE IF EXISTS performance;
CREATE TEMPORARY TABLE performance AS
SELECT time_in, time_out, day FROM attendance WHERE employee_id = id;
SET ##session.sql_notes = 1;
END