Related
I am declaring variables inside the procedure and setting those values to result from another query.when executed it is giving null.
version:8.0.16
call putrequest('x',"jiraUPM","ASE-12345","inprogress","testcybsjira.com");
requestId and reqid are not null.but it taking null value .
create procedure `putrequest`(in `employeeId` varchar(15),in `reqtype`
varchar(15),in `ticketId` varchar(15),in `status` varchar(15),in `details`
varchar(100))
begin
declare `rid` int;
declare `reqType` int;
select `requestId` into `reqType` from `requesttype` where `request`=`reqtype`;
select `reqId` into `rid` from `employee` where `empId`=`employeeId`;
insert into `requests` values(rid,reqType,`ticketId`,NOW(),NOW(),`status`,`details`);
end
Error executing SQL statement. Column 'reqId' cannot be null - Connection: Connection 1: 93ms
If either of the SELECT queries doens't find a matching row, the corresponding variable will be NULL, and you'll get an error when you try to insert it. You need to check for that before doing the INSERT.
But there's no need for separate SELECT queries and variables, use INSERT INTO ... SELECT ...
INSERT INTO requests
SELECT e.reqId, r.requestId, ticketId, NOW(), NOW(), status, details
FROM requesttype AS r
CROSS JOIN employee AS e
WHERE r.request = reqtype
AND e.empId = employeeId
If reqtype or employeeId can't be found, the join won't return any rows, so nothing will be inserted.
It creates a problem because of the same variable name "reqtype" (declare as a procedure parameter) and "reqType" (Declare as procedure variable)
It considers the null value for reqtype and not return any record.
MySQL is case insensitive . Be careful while given variable name.
DELIMITER $$
create procedure `putrequest`(in `employeeId` varchar(50),in `rtype`
varchar(50),in `ticketId` varchar(15),in `status` varchar(15),in `details`
varchar(100))
begin
declare `rid` int;
declare `reqType` int;
select `reqId` into `rid` from `employee` where `empId`=`employeeId`;
select `requestId` into `reqType` from requesttype where `request`=`rtype`;
insert into `requests` values(rid,reqType,`ticketId`,NOW(),NOW(),`status`,`details`);
end$$
DELIMITER ;
DEMO
In Postgresql, trigger can be created by using trigger procedure. This is handy way of creating trigger. Using the same trigger procedure, it is possible to create several triggers and apply it even for several different tables. I am wondering if there is any MySQL equivalent for it. I am inspired by this blog post which creates a generic trigger for database auditing. My plan is to implement the similar approach by using MySQL. But, is it really possible create that kind of generic trigger by MySQL?
After doing some research, I have understood that there is no direct way to create generic trigger in MySQL. Even dynamic SQL like prepare statement, execute statement are not allowed inside trigger in MySQL.
I have found a workaround to generate trigger dynamically. Suppose we have a customer table:
CREATE TABLE customer (
id bigint(20) NOT NULL AUTO_INCREMENT,
created_on datetime DEFAULT NULL,
first_name varchar(100) NOT NULL,
last_name varchar(100) NOT NULL,
PRIMARY KEY (id)
)
A revision info table:
CREATE TABLE REVINFO (
REV int(11) NOT NULL AUTO_INCREMENT,
REVTSTMP bigint(20) DEFAULT NULL,
PRIMARY KEY (REV)
)
An audit table:
CREATE TABLE customer_AUD (
id bigint(20) NOT NULL,
REV int(11) NOT NULL,
REVTYPE tinyint(4) DEFAULT NULL,
created_on datetime DEFAULT NULL,
first_name varchar(100) DEFAULT NULL,
last_name varchar(100) DEFAULT NULL,
PRIMARY KEY (id, REV),
KEY FK_REV (REV)
)
Now we will crate a procedure that will take a table name and generate SQL for create audit related trigger for table.
DROP PROCEDURE IF EXISTS `proc_trigger_generator`;
DELIMITER $$
CREATE PROCEDURE `proc_trigger_generator` (IN tableName VARCHAR(255))
BEGIN
DECLARE triggerSQL TEXT DEFAULT "";
DECLARE cols TEXT DEFAULT "";
DECLARE col_values TEXT DEFAULT "";
DECLARE insert_query TEXT DEFAULT "";
DECLARE colName TEXT DEFAULT "";
DECLARE done INT DEFAULT FALSE;
DECLARE cursorDS CURSOR FOR SELECT column_name FROM information_schema.columns cols
WHERE cols.table_name = CONCAT(tableName, '_AUD')
and (column_name != 'REV' && column_name != 'REVTYPE');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
SET triggerSQL = 'DELIMITER ;; \n\n';
SET triggerSQL = CONCAT(triggerSQL, 'drop trigger if exists tr_', tableName, '_update_audit;; \n\n');
SET triggerSQL = CONCAT(triggerSQL, 'create trigger tr_', tableName, '_update_audit \n');
SET triggerSQL = CONCAT(triggerSQL, 'after update \n');
SET triggerSQL = CONCAT(triggerSQL, '\t on ', tableName, '\n');
SET triggerSQL = CONCAT(triggerSQL, 'for each row \n');
SET triggerSQL = CONCAT(triggerSQL, 'begin \n');
SET triggerSQL = CONCAT(triggerSQL, '\t DECLARE tmpInt INT; \n');
SET triggerSQL = CONCAT(triggerSQL, '\t SELECT COALESCE(MAX(REV), 0) FROM REVINFO into tmpInt; \n\n');
SET triggerSQL = CONCAT(triggerSQL, '\t INSERT INTO REVINFO (REV, REVTSTMP) VALUES (tmpInt+1, CURRENT_TIMESTAMP()); \n\n');
SET insert_query = CONCAT(insert_query, 'INSERT INTO ', CONCAT(tableName, '_AUD'), ' (');
OPEN cursorDS;
ds_loop: LOOP
FETCH cursorDS INTO colName;
IF done THEN
LEAVE ds_loop;
END IF;
SET cols = CONCAT(cols, colName, ', ');
SET col_values = CONCAT(col_values, 'new.', colName, ', ');
END LOOP;
SET insert_query = CONCAT(insert_query, cols, 'REV, REVTYPE) VALUES \n');
SET insert_query = CONCAT(insert_query, '\t\t(', col_values, 'tmpInt+1, 1', ');');
CLOSE cursorDS;
SET triggerSQL = CONCAT(triggerSQL, '\t ',insert_query, ' \n\n');
SET triggerSQL = CONCAT(triggerSQL, 'end;; \n\n');
SET triggerSQL = CONCAT(triggerSQL, 'DELIMITER ; \n\n');
SELECT triggerSQL;
END $$
DELIMITER ;
call proc_trigger_generator('customer');
Calling the procedure by using customer table name generates SQL for the desired trigger:
DELIMITER ;;
drop trigger if exists tr_customer_update_audit;;
create trigger tr_customer_update_audit
after update
on customer
for each row
begin
DECLARE tmpInt INT;
SELECT COALESCE(MAX(REV), 0) FROM REVINFO into tmpInt;
INSERT INTO REVINFO (REV, REVTSTMP) VALUES (tmpInt+1, CURRENT_TIMESTAMP());
INSERT INTO customer_AUD (id, created_on, first_name, last_name, REV, REVTYPE) VALUES
(new.id, new.created_on, new.first_name, new.last_name, tmpInt+1, 1);
end;;
DELIMITER ;
The above trigger should do auditing tasks for customer table.
The trigger generator procedure can be applied to any other table now that we wish to apply auditing related tasks.
Anyone know why my query not work well
ALTER PROCEDURE [dbo].[SPMonStoVal]
#StoDate varchar(25),
#StockStatus varchar(2) OUT
AS
DECLARE
#TbName varchar(25)
SET #TbName = 'zSTO:'+#StoDate
EXEC('IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[dbo].['+#TbName+']'') AND type in (N''U''))
SET #StockStatus = ''1''
ELSE
SET #StockStatus = ''0'' ')
Anyone know why my query not work well?
Why use Execute text just use simple statement
ALTER PROCEDURE [dbo].[SPMonStoVal]
#StoDate varchar(25),
#StockStatus varchar(2) OUT
AS
BEGIN
DECLARE
#TbName varchar(25)
SET #TbName = 'zSTO:'+#StoDate
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(CAST(#TbName AS NVARCHAR(100))) AND type in (N'U'))
SET #StockStatus = '1'
ELSE
SET #StockStatus = '0'
END
My applications calls a stored procedure as required by my use case. The stored procedure insert records into two tables related by primary and foreign key constraints.
This means PatientNumber in Visit table must exist in the Patient table.
When I debug this procedure no value is display after setting initial values.
I am new to this, please help.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[Add_Patient_Visit]
AS
BEGIN TRANSACTION
SET NOCOUNT ON;
declare #Visit_Number Varchar(50)
declare #Prescription_Number Varchar(50)
declare #Visit_Date Datetime = GETDate()
set #Visit_Number = '25684956555'
set #Visit_Date = GETDATE()
set #Prescription_Number = '653214658'
INSERT INTO Visits(Visit_Number, Visit_Date, Patient_Number)
VALUES(#Visit_Number, #Visit_Date, #Patient_Number)
IF ##ERROR <> 0
BEGIN
ROLLBACK
RETURN
END
declare #Patient_Number Varchar(50)
declare #FirstName Varchar(50)
declare #LastName Varchar(50)
declare #Trible Varchar(50)
declare #Gender Varchar(5)
declare #Date_Of_Birth Datetime
INSERT INTO Patient(Patient_Number, FirstName, LastName, Tribe, Gender, Date_Of_Birth)
VALUES (#Patient_Number, #FirstName, #LastName, #Trible, #Gender, #Date_Of_Birth)
IF ##ERROR <> 0
BEGIN
ROLLBACK
RETURN
END
COMMIT
GO
There is a mistake in above procedure. You are using #Patient_Number before declaring, while inserting in table 'Visits'. Declare it in begining, like :
declare #Patient_Number Varchar(50)
declare #Visit_Number Varchar(50)
declare #Prescription_Number Varchar(50)
declare #Visit_Date Datetime = GETDate()
set #Visit_Number = '25684956555'
set #Visit_Date=GETDATE()
set #Prescription_Number='653214658'
Insert into Visits(Visit_Number,Visit_Date,Patient_Number)
Values(#Visit_Number,#Visit_Date,#Patient_Number)
IF ##ERROR <> 0
BEGIN
ROLLBACK
RETURN
END
declare #FirstName Varchar(50)
declare #LastName Varchar(50)
declare #Trible Varchar(50)
declare #Gender Varchar(5)
declare #Date_Of_Birth Datetime
INSERT INTO Patient(Patient_Number,FirstName,LastName,Tribe,Gender,Date_Of_Birth)
VALUES (#Patient_Number,#FirstName,#LastName,#Trible,#Gender,#Date_Of_Birth)
IF ##ERROR <> 0
BEGIN
ROLLBACK
RETURN
END
COMMIT
I want to create a stored procedure which will do matching of two tables. My requirement is to match two tables based on the columns user passes as an input.
Syntax:
CREATE PROCEDURE reconcile.matchTables(
IN TAB1 VARCHAR(25),
IN TAB1 VARCHAR(25),
IN COLS1 VARCHAR(250) ,
IN COLS2 VARCHAR(250))
EX:
matchTables('table1', 'table2', 'col1#col2#col3#col4' , 'col2#col13#col1#col8')
Now the stored procedure should form the where clause like the following
table1.col1 = table2.col2
and table1.col2 = table2.col13
and table1.col3 = table2.col1
and table1.col4 = table2.col8
MySQL does not include a function to split a delimited string. However, it’s very easy to create your own function.
User define function:
CREATE [AGGREGATE] FUNCTION function_name
RETURNS {STRING|INTEGER|REAL|DECIMAL}
Function:
CREATE FUNCTION SPLIT_STR(
x VARCHAR(255),
delim VARCHAR(12),
pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
delim, '');
Usage:
SELECT SPLIT_STR(string, delimiter, position)
Answer
Table 1
CREATE TABLE `Table1` (
`Col1` varchar(100) DEFAULT NULL,
`Col2` varchar(100) DEFAULT NULL,
`Col3` varchar(100) DEFAULT NULL,
`Col4` varchar(100) DEFAULT NULL,
`DummyColumn` varchar(45) DEFAULT NULL
)
Table 2
CREATE TABLE `Table2` (
`col2` varchar(100) DEFAULT NULL,
`col13` varchar(100) DEFAULT NULL,
`col1` varchar(100) DEFAULT NULL,
`col8` varchar(100) DEFAULT NULL
)
Stored Procedure
CREATE DEFINER=`Connect7827`#`%` PROCEDURE `reconcile.matchTables`(
IN TAB1 VARCHAR(25),
IN TAB2 VARCHAR(25),
IN COLS1 VARCHAR(250) ,
IN COLS2 VARCHAR(250))
StartfromHere: BEGIN
DECLARE NoOfColumnInTable1 INT unsigned DEFAULT 0;
DECLARE NoOfColumnInTable2 INT unsigned DEFAULT 0;
Declare Column1Count int default 1;
Declare Column2Count int default 1;
Declare vPickOneValue varchar(100);
Declare querystring varchar(8000);
Declare NoOFRowsInFinalResult int default 1;
Declare _Tab1 varchar(1000);
Declare _TAB2 varchar(1000);
Declare _COLS1 varchar(1000);
Declare _COLS2 varchar(1000);
-- Column Names for Table 1
DROP TEMPORARY TABLE IF EXISTS Table1_Columns;
CREATE TEMPORARY TABLE Table1_Columns(Column_Name varchar(100));
SET #buffer= CONCAT_WS('','insert into Table1_Columns(Column_Name)
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = ',"'",TAB1,"'");
-- Select #buffer;
PREPARE stmt FROM #buffer;
EXECUTE stmt;
-- Column Names for Table 2
DROP TEMPORARY TABLE IF EXISTS Table2_Columns;
CREATE TEMPORARY TABLE Table2_Columns(Column_Name varchar(100));
SET #buffer= CONCAT_WS('','insert into Table2_Columns(Column_Name)
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = ',"'",TAB2,"'");
-- Select #buffer;
PREPARE stmt FROM #buffer;
EXECUTE stmt;
Set NoOfColumnInTable1=(Select count(*) from Table1_Columns);
Set NoOfColumnInTable2=(Select count(*) from Table2_Columns);
-- Select NoOfColumnInTable1,NoOfColumnInTable2;
if (NoOfColumnInTable1=0) then
Select 'Table 1 not found in database'as'Result';
leave StartfromHere;
end if;
if (NoOfColumnInTable2=0) then
Select 'Table 2 not found in database' as'Result' ;
leave StartfromHere;
end if;
IF (NoOfColumnInTable1!=NoOfColumnInTable2) then
Select 'No of column to be joined must be equal.'as'Result';
leave StartfromHere;
end if;
DROP TEMPORARY TABLE IF EXISTS BasedOn_Col1_List;
CREATE TEMPORARY TABLE BasedOn_Col1_List(ID int NOT NULL AUTO_INCREMENT, Column_Name varchar(100), PRIMARY KEY (id));
while Column1Count< NoOfColumnInTable1+1 do
set #Query=CONCAT_WS('' ,"insert into BasedOn_Col1_List(Column_Name) Select SUBSTRING_Index('",COLS1,"','#',",Column1Count,");");
-- Select #Query as'Value';
PREPARE stmt1 FROM #Query;
EXECUTE stmt1;
SET Column1Count=Column1Count+1;
end while;
SET Column1Count=1;
WHILE Column1Count<=NoOfColumnInTable1 do
SET vPickOneValue=(Select Concat(Column_Name,"#") from BasedOn_Col1_List where ID=Column1Count);
update BasedOn_Col1_List set Column_Name=replace(Column_Name,vPickOneValue,"") where ID<>Column1Count;
-- Select vPickOneValue;
SET Column1Count=Column1Count+1 ;
end while;
-- Preapre Table from Column2 Parameter
DROP TEMPORARY TABLE IF EXISTS BasedOn_Col2_List;
CREATE TEMPORARY TABLE BasedOn_Col2_List(ID int NOT NULL AUTO_INCREMENT, Column_Name varchar(100), PRIMARY KEY (id));
while Column2Count< NoOfColumnInTable2+1 do
set #Query=CONCAT_WS('' ,"insert into BasedOn_Col2_List(Column_Name) Select SUBSTRING_Index('",COLS2,"','#',",Column2Count,");");
-- Select #Query as'Value';
PREPARE stmt2 FROM #Query;
EXECUTE stmt2;
SET Column2Count=Column2Count+1;
end while;
SET Column2Count=1;
WHILE Column2Count<=NoOfColumnInTable2 do
SET vPickOneValue=(Select Concat(Column_Name,"#") from BasedOn_Col2_List where ID=Column2Count);
update BasedOn_Col2_List set Column_Name=replace(Column_Name,vPickOneValue,"") where ID<>Column2Count;
-- Select vPickOneValue;
SET Column2Count=Column2Count+1 ;
end while;
DROP TEMPORARY TABLE IF EXISTS TableFromColumnList;
CREATE TEMPORARY TABLE TableFromColumnList
( ID int NOT NULL AUTO_INCREMENT,
Table1Name varchar(100),
Column_Name_Table1 varchar(100),
Table2Name varchar(1000),
Column_Name_Table2 varchar(100),
PRIMARY KEY (id)
);
Insert into TableFromColumnList(Column_Name_Table1,Column_Name_Table2,Table1Name,Table2Name)
select t1.Column_Name,t2.Column_Name,TAB1,TAB2
from BasedOn_Col1_List t1 , BasedOn_Col2_List t2 where t1.Id=t2.id;
-- -- Preparing the final Result ----------------
While NoOFRowsInFinalResult<=NoOfColumnInTable2 do -- / Or NoOFRowsInFinalResult<=NoOfColumnInTable2 --
SET _Tab1 =(Select Table1Name from TableFromColumnList where Id=NoOFRowsInFinalResult);
SET _COLS1 =(Select Column_Name_Table1 from TableFromColumnList where Id=NoOFRowsInFinalResult);
SET _TAB2 =(Select Table2Name from TableFromColumnList where Id=NoOFRowsInFinalResult);
SET _COLS2 =(Select Column_Name_Table2 from TableFromColumnList where Id=NoOFRowsInFinalResult);
IF NoOFRowsInFinalResult=1 then
SET querystring =concat_ws("" , querystring,_Tab1,".", _COLS1 , "=",_Tab2,".", _COLS2," ");
else
SET querystring =concat_ws("" , querystring ,"and",_Tab1,".", _COLS1 , "=" ,_Tab2,".", _COLS2 ," ");
end if;
SET NoOFRowsInFinalResult=NoOFRowsInFinalResult+1 ;
End while;
SET querystring=concat_ws("","Select * from ",TAB1,", " ,TAB2," where ",querystring);
Select querystring;
END
CREATE PROCEDURE matchTables
#TAB1 VARCHAR(25),
#TAB2 VARCHAR(25),
#COLS1 VARCHAR(250) ,
#COLS2 VARCHAR(250)
AS
BEGIN
DECLARE #WHEREstring VARCHAR(MAX)
SET #WHEREstring =
'
WHERE
'
SELECT #WHEREstring = #WHEREstring + #TAB1 +'.'+ tab1.col+' = '+#TAB2+'.' + tab2.col +' AND
'
FROM
(
SELECT QUOTENAME(split.a.value('.','VARCHAR(100)')) AS col, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNum
FROM
(
SELECT Cast ('<M>' + Replace(#COLS1, '#', '</M><M>')+ '</M>' AS XML) AS Tab1Data
) AS A
CROSS apply Tab1Data.nodes ('/M') AS Split(a)
) tab1
INNER JOIN
(
Select QUOTENAME(AliasSplit.c.value('.', 'varchar(100)')) AS col, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNum
FROM
(
SELECT Cast ('<A>' + Replace(#COLS2, '#', '</A><A>')+ '</A>' AS XML) AS Tab2Data
) AS A
CROSS apply Tab2Data.nodes ('/A') AS AliasSplit(c)
) tab2
ON tab1.RowNum = tab2.RowNum
SET #WHEREstring= LEFT(#WHEREstring, LEN(#WHEREstring) - 8)
print #WHEREstring
END
Now, execute it using :::
EXEC matchTables 'table1', 'table2', 'col1#col2#col3#col4' , 'col2#col13#col1#col8'
i hope you got the desired where clause. cheers
You can build your own function:
CREATE FUNCTION String_split(inp VARCHAR(255),del VARCHAR(255),loc INT)
RETURNS VARCHAR(255)
RETURN REPLACE(Substring(Substring_index(inp, del,loc),LENGTH(Substring_index(inp, del, loc-1)) + 1),del, '');
CHAR_LENGTH - return correct length in chars
CREATE FUNCTION SPLIT_STR(
x VARCHAR(255),
delim VARCHAR(12),
pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
CHAR_LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
delim, '');