I am new to stored procedure in PostgreSQL (pgSQL) .I need some one help to crack my problem .I am doing the migration process from oracle to PostgreSQL for that I have used some stored procedure concept. I have tried in SQL stored procedure its working in SQL, but same code i have trying to convert into pgSQL. I have faced a issue in line by line .can any one help me to convert same code SQL into PostgreSQL. i have attached my SQL procedure code below. can any one suggest me aright way to process the code.
code:
delimiter;
drop procedure if exists patient_form_values;
delimiter $$
create procedure patient_form_values()
begin
declare columnName varchar(200) ;
declare done tinyint default 0;
declare cur1 cursor for select distinct COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'CASESHEETCOMPLAINTS' and table_schema='hms_empty_copy';
declare continue handler for not found set done = 1;
open cur1;
read_loop : loop
fetch from cur1 into columnName;
if done then leave read_loop;
end if;
set #insertValues := concat('INSERT INTO patient_form_temp(patient_id, form_template_id, creator_id, created_date)
SELECT c.patient_id as patient_id, 41 AS form_template_id, 2 AS creator_id, c.created_date AS created_date
FROM CASESHEETCOMPLAINTS c
WHERE c.', columnName,' IS NOT NULL GROUP BY c.patient_id, c.created_date');
select #insertValues;
prepare stmt from #insertValues;
execute stmt;
end loop;
close cur1;
end $$
delimiter ;
call patient_form_values();
drop procedure if exists patient_form_values;
--To delete the empty records.
DELETE FROM patient_form WHERE id NOT IN(SELECT patient_form_id FROM patient_form_value);
insert into patient_form(patient_id, form_template_id, creator_id, created_date)select patient_id, form_template_id, creator_id, created_date from patient_form_temp GROUP BY patient_id, created_date
Related
For fun I am messing with phpmyadmin to get myself familiarized with sql but I am stuck at a issue. I am trying to make it so I can automate the organization of employees into tables based on department. I have a procedure I have been working on to use a different table that lists all the departments into a cursor and uses the cursor to fill in the blanks of a create table as query. But when I try to run the creation of the procedure phpmyadmin errors out saying
1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version for the right syntax to use
near '' at line 3
but in my code line 3 is just BEGIN. What do I need to do to make this work?
CREATE PROCEDURE deptOrganize()
BEGIN
DECLARE counting INT DEFAULT 0;
DECLARE location VARCHAR(MAX);
DECLARE curs1 CURSOR SELECT Department FROM departments;
OPEN curs1;
WHILE counting < 15 DO
FETCH curs1 INTO location;
CREATE TABLE location AS
SELECT * FROM employees
WHERE employees.Department = location ;
END WHILE;
END;
You can't use a variable for the table name in CREATE TABLE. You have to create dynamic SQL with the PREPARE statement.
You also need to use the DELIMITER directive to change the query delimiter from ;, so you can use that as the statement delimiter within the procedure.
And you forgot to increment counting, so you have an infinite loop.
DELIMITER $$
CREATE PROCEDURE deptOrganize()
BEGIN
DECLARE counting INT DEFAULT 0;
DECLARE curs1 CURSOR SELECT Department FROM departments;
OPEN curs1;
WHILE counting < 15 DO
FETCH curs1 INTO #location;
SET #sql = CONCAT('CREATE TABLE ', #location, ' AS
SELECT * FROM employees
WHERE employees.Department = ?') ;
PREPARE stmt FROM #sql;
EXECUTE stmt USING #location;
DEALLOCATE PREPARE stmt;
SET counting = counting + 1;
END WHILE;
END$$
My question might be simple for you, if you're used to MySQL. I'm used to PostgreSQL SGBD and I'm trying to translate a PL/PgSQL script to MySQL.
Here is what I have :
delimiter //
CREATE TRIGGER pgl_new_user
AFTER INSERT ON users FOR EACH ROW
BEGIN
DECLARE m_user_team_id integer;
SELECT id INTO m_user_team_id FROM user_teams WHERE name = "pgl_reporters";
DECLARE m_projects_id integer;
DECLARE cur CURSOR FOR SELECT project_id FROM user_team_project_relationships WHERE user_team_id = m_user_team_id;
OPEN cur;
ins_loop: LOOP
FETCH cur INTO m_projects_id;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT INTO users_projects (user_id, project_id, created_at, updated_at, project_access)
VALUES (NEW.id, m_projects_id, now(), now(), 20);
END LOOP;
CLOSE cur;
END//
But MySQL Workbench gives me an error on DECLARE m_projects_id. I don't really understand because I've the same instruction two lines above...
Any hints ?
EDIT: neubert solved this error. Thanks.
But yet, when I try to insert into users :
Error Code: 1329. No data - zero rows fetched, selected, or processed
Do you have any idea ? Or better, do you know how I can get a better error message ?
All DECLAREs need to be at the top. ie.
delimiter //
CREATE TRIGGER pgl_new_user
AFTER INSERT ON users FOR EACH ROW
BEGIN
DECLARE m_user_team_id integer;
DECLARE m_projects_id integer;
DECLARE cur CURSOR FOR SELECT project_id FROM user_team_project_relationships WHERE user_team_id = m_user_team_id;
SET #m_user_team_id := (SELECT id FROM user_teams WHERE name = "pgl_reporters");
OPEN cur;
ins_loop: LOOP
FETCH cur INTO m_projects_id;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT INTO users_projects (user_id, project_id, created_at, updated_at, project_access)
VALUES (NEW.id, m_projects_id, now(), now(), 20);
END LOOP;
CLOSE cur;
END//
Agree with neubert about the DECLARE statements, this will fix syntax error. But I would suggest you to avoid using openning cursors, they may be slow.
For your task: use INSERT...SELECT statement which will help you to copy data from one table to another using only one query.
INSERT ... SELECT Syntax.
I have written a procedure that creates a temporary table and executes a query by fetching the rows from the temporary table.I have around 13486 rows in the temporary table.But when i am calling the procedure i observed that the procedure is getting terminated after fetching 107 rows from the temporary table.Moreover i also observed that this value is not constant..Sometimes it is 107 the other time it is 114 and some other time it is just 100.Why this happens?Please need help?Somebody please..Here is my procedure.And i came to know that while loop will terminate for >1000 iterations.Please suggest me a method to overcome this.
DELIMITER $$
DROP PROCEDURE IF EXISTS `lookup`.`test` $$
CREATE PROCEDURE `lookup`.`test` ()
BEGIN
CREATE TEMPORARY TABLE lookup.airportname(id int AUTO_INCREMENT,PRIMARY KEY(id))
AS (select distinct airport_id from lookup.airport);
SET #num=0;
SET #arpt=NULL;
SELECT count(*) INTO #num FROM airportname;
SET #i=0;
while #i<#num do
SELECT airport_id INTO #arpt FROM airportname WHERE id=#i;
select #arpt,#i;
set #i=#i+1;
end while;
END $$
DELIMITER ;
I am using mysql query browser.Thank you.
If you want to insert value into id Then it should not be auto_increment. - Remove auto_increment from table definition, it should work
delimiter |
create procedure employee_select()
Begin
Declare empno,done int(9);
Declare emp_select Cursor for select emp_no from gross_salary ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
Open emp_select; // cursor opening
read_loop: loop // start looping all the datas one by one
fetch emp_select into empno; // fetching the select value into variable empno
//note :variable name should not be same as columne name in select statement"
IF done THEN
LEAVE read_loop; // if no more rows, this makes it to leave the loop"
END IF;
//Enter the code you want do for each row
end loop;
close emp_select;
End |
delimiter ;
Problem:
Hi I've got two stored procedures, that I try to run from another one.
- If I call them one after the other from phpmysqladmin, everything works fine.
- If I call the stored procedure, that calls the other two, I don't get an error. So far so good. But the problem is, that the operations from the second stored procedure aren't executed.
Already tried to run it in just one sp...
I also tried to run both stored procedures (sp1,sp2) in one stored procedure, with the same effect.
Could that be the problem?
In the first sp I use a statement like this:
Select #var:= ....
Here is the code:
In the first stored procedure I generate a dynamic query and execute it.
Procedure 1
CREATE PROCEDURE `sp_prepare_valid_choices`(IN p_request_id Bigint)
BEGIN
DECLARE num_rows INT DEFAULT 0;
DECLARE no_more_rows BINARY;
DECLARE no_more_subrows BINARY;
DECLARE loop_cntr INT DEFAULT 0;
DECLARE var_choice_group BIGINT DEFAULT 0;
-- Declare Cursor for the loop through the constraint_groups
DECLARE cur_constraint_group CURSOR FOR
SELECT distinct choice_constraint_group FROM casainte_choice_constraint
WHERE choice_id_rule_parameter IN (SELECT choice_id FROM casainte_request_detail
where request_id = p_request_id);
-- DECLARE 'handlers' for exceptions
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_rows := TRUE;
-- DELETE OLD VALUES
DELETE FROM tmp_casainte_valid_choices
WHERE request_id = p_request_id;
DELETE FROM tmp_casainte_valid_choices_for_request
WHERE request_id = p_request_id;
-- OPEN CURSOR AN PROCESS CONSTRAINT_GROUPS
OPEN cur_constraint_group;
SELECT FOUND_ROWS() INTO num_rows;
choice_group_loop: LOOP
FETCH cur_constraint_group
INTO var_choice_group;
IF no_more_rows THEN
CLOSE cur_constraint_group;
LEAVE choice_group_loop;
END IF;
-- PAYLOAD
-- INSERT THE VALID CHOCIES INTO tmp_casainte_valid_choices
SELECT #var_sql_query := CONCAT('INSERT INTO tmp_casainte_valid_choices ','SELECT ',p_request_id,' as request_id, `casainte_choice_constraint`.`choice_constraint_id`,`casainte_choice_constraint`.`choice_constraint_group`
,AVG(IF (`casainte_request_detail`.`choice_varchar_value`', `casainte_choice_constraint`.`choice_constraint_operator`, '\'',`casainte_choice_constraint`.`choice_constraint_value`, '\'',',1,0 )) AS VALID
FROM `casainte_choice_constraint`
LEFT JOIN `casainte_request_detail` ON `casainte_request_detail`.`choice_id` = `casainte_choice_constraint`.`choice_id_rule_parameter`
WHERE `casainte_choice_constraint`.choice_constraint_group =' , var_choice_group,
' GROUP BY `casainte_choice_constraint`.choice_constraint_group')
FROM `casainte_choice_constraint` WHERE `casainte_choice_constraint`.choice_constraint_group = var_choice_group;
PREPARE SQL_STATEMENT FROM #var_sql_query;
EXECUTE SQL_STATEMENT;
-- INCREMENT THE COUNTER
SET loop_cntr = loop_cntr + 1;
END LOOP choice_group_loop;
END$$
Procedure 2
In the second stored procedure I insert the values into a table.
delimiter $$
CREATE PROCEDURE `sp_insert_valid_choices`(IN p_request_id Bigint)
BEGIN
INSERT INTO tmp_casainte_valid_choices_for_request
(request_id, choice_id)
SELECT DISTINCT p_request_id, choice_id FROM casainte_choice ac
-- RULE 1 ALL CHOICES WITHOUT CONSTRAINTS
WHERE ac.choice_id NOT IN (SELECT choice_id_rule_target FROM casainte_choice_constraint)
-- RULE 2 ALL CHOICES WITH CONSTRAINTS, THAT ARE NOT YET ANSWERED
OR ac.choice_id NOT IN (SELECT choice_id_rule_target FROM casainte_choice_constraint
WHERE choice_id_rule_parameter IN (SELECT choice_id FROM casainte_request_detail WHERE request_id = p_request_id))
-- RULE 3 ALL CHOICES WITH CONSTRAINTS, THAT ARE TRUE
OR ac.choice_id IN (SELECT choice_id_rule_target FROM casainte_choice_constraint
WHERE choice_constraint_group IN (SELECT choice_constraint_group FROM tmp_casainte_valid_choices WHERE request_id = p_request_id AND VALID = 1));
END$$
Procedure 3
The third stored procedure calls the 1st sp, then the 2nd sp.
delimiter $$
CREATE PROCEDURE `sp_generate_valid_choices`(IN p_request_id Bigint)
BEGIN
Call `sp_prepare_valid_choices`(p_request_id);
Call `sp_insert_valid_choices`(p_request_id);
END$$
You don't have "delimiter $$" at the top of Procedure 1. Could this be causing the problem?
I'm working on an old database already in use for years and really crappy designed.
There is a table, "Articles", which contains a "code" column that will be our PK.
And many tables like "idXXXXX" where XXXXX is a "code" value with exactly the same structure.
I looked at the application using this database and saw that relations between tables is made there.
I'm not affraid of redesign the database access in the application, but I don't want to lose years of entries in the database.
I want to create a "campain" table which will have an "id" PK and a "id_code" as FK linking "campain" to "articles"
I'm not a SQL master but I know I can get tables names with
SELECT TABLE_NAME FROM INFORMATION_SCHEMA WHERE TABLE_NAME LIKE 'id%'
But I have really no idea about how to deal with the result (which is fine).
So how can I access to every tables named "idXXX" and insert every rows in the "campain" table + set "id_code" column to "XXX"?
Here is the procedure I saved (I didn't add every fields in the INSERT line for testing purpose) :
CREATE PROCEDURE JoinAllTables()
BEGIN
DECLARE done INT default 0;
DECLARE tableName CHAR(9);
DECLARE buffStr CHAR(7);
DECLARE buffId INT default 0;
DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'id%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO tableName;
IF done THEN
LEAVE read_loop;
END IF;
SET buffStr = SUBSTRING(tableName, 3);
SET buffId = CAST(buffStr AS SIGNED);
set #sql = CONCAT("INSERT INTO campagnes(id, id_code) SELECT null, bufId FROM ",tableName); # Dynamically building sql statement
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur1;
END;
As u can see, I sub 'idXXXXX' to 'XXXXX' then CAST it AS INTEGER (SIGNED).
But I guess that in the "INSERT INTO" line, second tableName doesn't point to the variable. That's why I'm getting a
"#1446 - Tabble 'bddsoufflage.tablename'doesn't exist" Error :) Any idea ?
Edit: Updated answer
We can't have the tableName dynamically changed inside a prepared statement, so we must go through DynamicSQL to build the query using CONCAT, then compile the SQL with PREPARE, EXECUTE it and DEALLOCATE it.
DELIMITER //
CREATE PROCEDURE JoinAllTables()
BEGIN
DECLARE done INT default 0;
DECLARE tableName CHAR(9);
DECLARE buffStr CHAR(7);
DECLARE buffId INT default 0;
DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'id%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO tableName;
IF done THEN
LEAVE read_loop;
END IF;
SET buffStr = SUBSTRING(tableName, 3);
SET buffId = CAST(buffStr AS SIGNED);
set #sql = CONCAT("INSERT INTO campagnes(id, id_code) SELECT null, ", buffId, " FROM ",tableName); # Dynamically building sql statement
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur1;
END; //
See also this answer MySQL Pass table name to cursor select
Old answer
The procedure should look something like this. Thanks Mchl for providing an Insert Into query example, I simply added it to the rest of the procedure.
DELIMITER //
CREATE PROCEDURE JoinAllTables()
BEGIN
DECLARE done INT default 0;
DECLARE tableName CHAR(7); # Variable to contain table names CHAr(7) is assuming id + 5Xs as characters.
DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA WHERE TABLE_NAME LIKE 'id%'; # Create a cursor to iterate over the tables
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO tableName;
IF done THEN
LEAVE read_loop;
END IF;
#Your Insert statement here, using tableName as a field.
INSERT INTO campain (id, id_code, otherfields) SELECT null, tableName, otherfields FROM tableName;
END LOOP;
CLOSE cur1;
END;//
Easiest way would be to run the information_schema query you have within some script (PHP,Python,Perl - whichever suits you best) and use it's results to create queries like:
INSERT INTO
campain (id, id_code, otherfields)
SELECT
null, 'idXXXX', otherfields FROM idXXXX