So say I have a user defined function:
CREATE FUNCTION ADDRESS_EXISTS_FULL (
line_1 VARCHAR(64),
line_2 VARCHAR(64),
city VARCHAR(64),
state VARCHAR(32),
zip VARCHAR(10),
type INT(3)
)
RETURNS INT(1)
DETERMINISTIC
READS SQL DATA
BEGIN
DECLARE aid INT;
SET aid = NULL;
SELECT addressid INTO aid FROM dlp.address as a
WHERE a.line_1 = line_1
AND a.line_2 = line_2
AND a.city = city
AND a.state = state
AND a.zip = zip
AND a.address_type = type
LIMIT 1;
RETURN IF(aid IS NOT NULL, 1, 0);
END$$
How do I make it so that some of these are not necessary? Like say if type is not needed, is there anyway to call
SELECT ADDRESS_EXISTS_FULL(l1,l2,c, s, z)
or would that fail? And how do I make that function work?
Thanks.
Note: I don't need this function stored, it's a one off so it's in one big mysql script file.
You can rewrite the query inside stored function body to something like
SELECT addressid INTO aid FROM dlp.address as a
WHERE (a.line_1 = p_line_1 OR p_line_1 IS NULL)
AND (a.line_2 = p_line_2 OR p_line_2 IS NULL)
--.... etc
LIMIT 1;
Thus, if you pass null for a particular parameter, it will be ignored. Also, I'd recommend avoiding naming parameters exactly the same as fields in the table - it may lead to very subtle bugs (In the query above I prepended 'p_' to each parameter).
Finally, I'd not use DETERMINISTIC keyword for a function that is non-deterministic by nature.
Related
I have a stored procedure that I used with a search function I created. The query within the procedure is as follows:
CREATE DEFINER=`root`#`localhost` PROCEDURE `advanced_search`(IN major_name VARCHAR(45),
OUT major_code INT, IN classification VARCHAR(45), IN job_class VARCHAR(45))
BEGIN
SELECT major_id INTO major_code FROM major
WHERE major = major_name;
SET #classification = classification;
SELECT * FROM job WHERE (major = major_code) OR (classification LIKE '%#classification%') OR (job_type = job_class);
END
I am having a problem with LIKE keyword clause. I want to check if a value in the classification field contains or includes the #classification variable. For some reason when I single out the clause that uses that keyword (by removing the first and third clause in the WHERE statement) it does not return anything.
Is there any advice on how to fix this?
Also, is it common for the object that appears below to be found within the results object?
{
"fieldCount": 0,
"affectedRows": 0,
"insertId": 0,
"serverStatus": 34,
"warningCount": 0,
"message": "",
"protocol41": true,
"changedRows": 0
}
EDIT: Here is the query I call
set #major_name = 'Chemical Engineering';
set #major_code = 0;
set #classification = 'Freshman';
set #job_class = 'Assistant';
call aggie_soop.advanced_search(#major_name, #major_code, #classification, #job_class);
These are the results. This is the exact same as the original table
I don't think you need a user-defined variable, you can reference the procedure argument.
You can use the MySQL CONCAT() function to concatenate the percent sign literals with the value.
I prefer to qualify all column references, and use a naming convention for procedure variables that avoids name collisions. While MySQL doesn't care, it makes it much easier for the future reader to decipher the intent.
CREATE DEFINER=`root`#`localhost`
PROCEDURE `advanced_search`
( IN p_major_name VARCHAR(45)
, OUT p_major_code INT
, IN p_classification VARCHAR(45)
, IN p_job_clas VARCHAR(45)
)
BEGIN
SELECT m.major_id INTO p_major_code
FROM major m
WHERE m.major = p_major_name
LIMIT 1
;
SELECT j.*
FROM job j
WHERE (j.major = p_major_code)
OR (j.classification LIKE CONCAT('%',p_classification,'%')
OR (j.job_type = p_job_class)
;
END
(I believe it's possible to "read" the value of the OUT parameter within the procedure, but I've never done it before.)
Note that if the p_classification string is a zero length string, then every row with a non-NULL value in the classification column is going to be returned.
You may want something like this:
OR (p_classification <> '' AND j.classification LIKE CONCAT('%',p_classification,'%')
(But the specification isn't clear.)
A small change is needed:
CREATE DEFINER=`root`#`localhost` PROCEDURE `advanced_search`(IN major_name VARCHAR(45),
OUT major_code INT, IN classification VARCHAR(45), IN job_class VARCHAR(45))
BEGIN
SELECT major_id INTO major_code FROM major
WHERE major = major_name;
SET #classification = classification;
SELECT * FROM job WHERE (major = major_code) OR (classification LIKE '%' || #classification || '%') OR (job_type = job_class);
END
I have a stored procedure that returns a common query, I need to call it in several functions but some functions may call it through Period Id or others through Header Id, so far I would like to know how can I determine what param to use in order to retrive data properly, I have something like this implemented.
CREATE PROCEDURE dbo.GetTFDRecordInfo
#PeriodId int = null,
#HeaderId int = null
AS
BEGIN
SELECT
-- I have a lot more fields and joins here, that's why I need to get the statement in a single call through either period id or header id
*
From NT_CSRTNVPeriodInfo t
-- how can I make possible something like shown above, can I use a "Case When"?
Where (
/*
if #PeriodId is null
Where t.HeaderId = #HeaderId
if #HeaderId is null
Where t.PeriodId = #PeriodId
*/
)
END
GO
-- swtich between params
Exec NT_CSRTNVPeriodInfo null, 2654
Exec NT_CSRTNVPeriodInfo 196, null
This is the answer:
CREATE PROCEDURE dbo.GetTFDRecordInfo
#PeriodId int = null,
#HeaderId int = null
AS
BEGIN
SELECT
-- I have a lot more fields and joins here, that's why I need to get the statement in a single call through either period id or header id
*
From NT_CSRTNVPeriodInfo t
-- how can I make possible something like shown above, can I use a "Case When"?
Where ((#PeriodId IS NULL) or (t.PeriodId = #PeriodId))
And ((#HeaderId IS NULL) or (t.HeaderId = #HeaderId))
END
GO
You have to use conditional OR to check NULLs, if param is set, the second condition is checked, if not, the procedure will consider always true the statement and go to the next.
I am trying to write a Mysql Function to return a contactID if the record exists based on the parameters supplied, If the record is not present, I am adding the record and then returning the contactID of the new record.
But the function is throwing 1048error, Can you check and correct me if I went wrong in writing this.
DELIMITER $$
CREATE DEFINER=`root`#`%` FUNCTION `GetContactID`(accountNumber CHAR(45),UserID INT(11)) RETURNS char(1) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE ContactID INT DEFAULT 0;
SELECT ContactID INTO #ContactID FROM Contact WHERE AccountNumber = #accountNumber AND UserID = #UserID AND Status =1;
IF ContactID = 0 or ContactID is null THEN
INSERT INTO Contact(AccountNumber,UserID) VALUES (#accountNumber,#UserID);
SELECT ContactID INTO #ContactID FROM Contact WHERE AccountNumber = #accountNumber AND UserID = #UserID;
END IF;
RETURN ContactID;
END
Can someone help me where I went wrong.
Thanks
The problem results from mixing user variables, local variables and parameters.
#UserId is not the same as UserId - they are different variables.
UserId is also a name of column in the table.
User defined variables are wirtten as #var_name, are stored in the user session and can be used to pass values between differend stored routines that reference them, see this link for details: http://dev.mysql.com/doc/refman/5.7/en/user-variables.html
local variables are declared in stored routines using DECLARE keyword, their scope is local within the stored routine, see this link for details: http://dev.mysql.com/doc/refman/5.7/en/declare-local-variable.html
Parameters of function/procedure - they are declared in the procedure/function declaration, they are used to pass parameters to the stored routine from the caller, can be also used to return results from the routine to the caller (if declared as OUT or INOUT). Their scope is similar to local variables. For details see this link: http://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
Try this code:
DELIMITER $$
CREATE DEFINER=`root`#`%` FUNCTION `GetContactID`(p_accountNumber CHAR(45),p_UserID INT(11)) RETURNS char(1) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE v_ContactID INT DEFAULT 0;
SELECT ContactID INTO v_ContactID
FROM Contact
WHERE AccountNumber = p_accountNumber AND UserID = p_UserID AND Status =1;
IF v_ContactID = 0 or v_ContactID is null THEN
INSERT INTO Contact(AccountNumber,UserID)
VALUES (p_accountNumber,p_UserID);
SELECT ContactID INTO v_ContactID FROM Contact
WHERE AccountNumber = p_accountNumber AND UserID = p_UserID;
END IF;
RETURN v_ContactID;
END;
Notice that:
function parameters are declared with prefix p_
local variables are declared with prefix v_
the function doesn't use any user variables (prefixed by #)
These prefixes help to avoid ambiguity - we know that p_UserID is a parameter, v_UserId is a local variable, and UserID is a column name in the table (If we would use #UserId, we knew that this was the user variable).
I write a function like the following. the purpose of this function is to return the place of a student by some specific exam in a branch.
DELIMITER $$
CREATE FUNCTION `getMerit`( branch VARCHAR(50), totalMark DECIMAL(19,2), comaSeparetedExamIds VARCHAR(200) ) RETURNS INT(11)
BEGIN
SET #comaSeparetedExamIds=comaSeparetedExamIds;
SET #branch =branch;
SET #marks=totalMark;
SELECT #place=COUNT(*)+1
FROM (
SELECT SUM(m.marks) marks
FROM marksheet m, studentinfo s
WHERE exam_id IN (#comaSeparetedExamIds)
AND m.student_roll=s.roll_no
AND s.branch LIKE CONCAT(#branch,'%')
GROUP BY m.student_roll
) AS a
WHERE a.marks>#totalMark;
RETURN #place;
END$$
DELIMITER ;
But It shows me an error. the Error is
Query : CREATE FUNCTION getMerit( branch varchar(50), totalMark
DECIMAL(19,2), comaSeparetedExamIds varchar(200) ) RETURNS int(11)
BEG... Error Code : 1415 Not allowed to return a result set from a
function
What mistake I made here, Can anyone please help me?
You can't name input variables with #. # is used for user variables, ie connection local variables that don't needs to be declared.
Also you can't have selects in functions.
Procedures can return result sets but return values.
Functions can return values but not result sets.
They also differs in how you use them.
select function_name(1) from dual;
select id, name, funcation_name(id, name) from anyTable;
call procedure_name(1);
And when assigning variables inside selects you need to do := and not =. In your code you are actually selecting true or false and not the count.
This should work.
DELIMITER $$
CREATE FUNCTION `getMerit`( branch VARCHAR(50), totalMark DECIMAL(19,2), comaSeparetedExamIds VARCHAR(200) ) RETURNS INT(11)
BEGIN
SET #comaSeparetedExamIds=comaSeparetedExamIds;
SET #branch =branch;
SET #marks=totalMark;
SELECT COUNT(*)+1 INTO #place
FROM (
SELECT SUM(m.marks) marks
FROM marksheet m, studentinfo s
WHERE exam_id IN (#comaSeparetedExamIds)
AND m.student_roll=s.roll_no
AND s.branch LIKE CONCAT(#branch,'%')
GROUP BY m.student_roll
) AS a
WHERE a.marks>#totalMark;
RETURN #place;
END$$
DELIMITER ;
This function:
CREATE FUNCTION `GetCardID`(numId INT) RETURNS int(11)
DETERMINISTIC
BEGIN
DECLARE retcard INT(11);
SELECT id
INTO retcard
FROM cards
WHERE `number` = numId
AND enabled = 1
LIMIT 1;
RETURN retcard;
END
Always returns null even when the query:
SELECT id FROM cards WHERE `number`=<Insert Value Here> AND ENABLED = 1 LIMIT 1;
returns a valid value for the same value used in and the function parameter.
For instance:
SELECT id FROM cards WHERE number=12345 AND ENABLED = 1 LIMIT 1;
-- returns an id, while
GetCardId(12345);
-- returns null
Any ideas what I'm missing here? I consider myself quite skilled at SQL, but a little green on SP's.
How big is the data that you are taking into your function? Is it possible that the number is larger than what will fit into an INT?
Christopher here is your function. Try this and it should work:
CREATE FUNCTION [dbo].[GetCardID]
(
#Num_ID INT
)
RETURNS int
AS
BEGIN
declare #retcard int
select Top 1 #retcard = id
FROM cards
where number = #num_Id
AND enabled = 1
return #retcard
END
Always returns NULL:
Get rid of DETERMINISTIC clause in Procedure definition. MySQL caches the responses from such procedure or functions.
Excerpt from MySQL:
A routine is considered “deterministic” if it always produces the same
result for the same input parameters, and “not deterministic”
otherwise. If neither DETERMINISTIC nor NOT DETERMINISTIC is given in
the routine definition, the default is NOT DETERMINISTIC. To declare
that a function is deterministic, you must specify DETERMINISTIC
explicitly
MySQL 5.5 - Creating Procedure or Function