Multiple Variable If Statement - mysql

I have recently been able to produce a procedure where if a variable is not set I can set it to null. Now I am now looking to have multiple variables, but if a value has not been set to that variable, for it then to return all rows.
BEGIN
DECLARE ps_Project_Leader VARCHAR(15);
DECLARE ps_RD_Plan VARCHAR (15);
DECLARE ps_Approval_Status VARCHAR (15);
DECLARE ps_Design_Plan VARCHAR (15);
SET ps_Project_Leader = ifnull(Project_Leader,null);
SET ps_RD_Plan = ifnull(RD_Plan,null);
SET ps_Approval_Status = ifnull(Approval_Status,null);
SET ps_Design_Plan = ifnull(Design_Plan,null);
SELECT pp.pid,
pp.description,
pp.approval_status,
pp.design_plan,
pp.rd_plan,
pp.estimated_completion,
pp.project_leader,
pp.actual_completion
FROM project_register pp
WHERE pp.project_leader =Project_Leader
OR Project_Leader is null
and pp.rd_plan =RD_Plan
OR RD_Plan is null
and pp.approval_status = Approval_Status
OR Approval_Status is null
and pp.design_plan = Design_Plan
OR Design_Plan is null
and
PP.actual_completion is null;
end
For instance if i have set 2 of the variables and not the other 2, I do not want it to search on the variables that have not been set.
Many Thanks in advance, if i have not made complete sense (i am new to this so i appologies) I will be happy to clear things up.

You need to parenthesize your WHERE expression correctly:
WHERE (pp.project_leader = ps_Project_Leader
OR ps_Project_Leader is null)
and (pp.rd_plan = ps_RD_Plan
OR ps_RD_Plan is null)
and (pp.approval_status = ps_Approval_Status
OR ps_Approval_Status is null)
and (pp.design_plan = ps_Design_Plan
OR ps_Design_Plan is null)
and PP.actual_completion is null;
because AND has higher precedence than OR.

You aren't referencing the local variables, only the procedure arguments. (It doesn't look like you actually need local variables.)
I prefer to use parens around the AND and OR predicates, even if they aren't required. I never have to lookup if AND or OR takes precedence when I use parens, because it doesn't matter, because I'm always specifying the precedence.
I'd help the reader out, and format my SQL like this:
WHERE ( pp.project_leader = Project_Leader OR Project_Leader IS NULL )
AND ( pp.rd_plan = RD_Plan OR RD_Plan IS NULL )
AND ( pp.approval_status = Approval_Status OR Approval_Status IS NULL )
AND ( pp.design_plan = Design_Plan OR Design_Plan IS NULL )
That way, each line is a "check" of a single column, which is either enabled (with a non-NULL value) or disabled with NULL value.
Really just personal preference, I just find it easier to read that way, even if the line is a little bit longer, I'd rather have the check all one one line.
Again, the local variables aren't needed.
But, you could just set local variables equal to the parameter values, and then reference the local variables in your SQL statement. That really helps out when a variable has the same name as a column, because if the are named the same, MySQL is going to assume it's a reference to column name rather than a variable name. Using a local variable gives you a chance to rename it so it won't be confused with a column name.
UPDATE
I just noticed that the parameter variables names ARE the same as the column names, and that's going to be a problem.
You want your variable names to be DIFFERENT than the column names. You want to make sure that the datatypes of the variables match the columns... later, when you change a column from VARCHAR(15) to VARCHAR(30), you'll need to revisit the procedure and change the definitions of the procedure arguments as well as the local variables.
BEGIN
-- local variable names are DISTINCT from any column name
-- in any table referenced by a query these are used in
DECLARE ps_Project_Leader VARCHAR(15);
DECLARE ps_RD_Plan VARCHAR(15);
...
-- copy parameter values to local variables
SET ps_Project_Leader = Project_Leader ;
SET ps_RD_Plan = RD_Plan ;
...
-- query references local variable names
...
WHERE ( pp.project_leader = ps_Project_Leader OR ps_Project_Leader IS NULL )
AND ( pp.rd_plan = ps_RD_Plan OR ps_RD_Plan IS NULL )
...

Related

want to Write a Stored Procedure in MYSQL [duplicate]

I have made a stored procedure. I want it to filter the data by different parameters. If I pass one parameter, it should be filtered by one; if I pass two, it should be filtered by two, and so on, but it is not working.
Can anyone help me please?
DROP PROCEDURE IF EXISTS medatabase.SP_rptProvince2;
CREATE PROCEDURE medatabase.`SP_rptProvince2`(
IN e_Region VARCHAR(45)
)
BEGIN
DECLARE strQuery VARCHAR(1024);
DECLARE stmtp VARCHAR(1024);
SET #strQuery = CONCAT('SELECT * FROM alldata where 1=1');
IF e_region IS NOT NULL THEN
SET #strQuery = CONCAT(#strQuery, ' AND (regionName)'=e_Region);
END IF;
PREPARE stmtp FROM #strQuery;
EXECUTE stmtp;
END;
AFAIK, you can't have a variable argument list like that. You can do one of a couple of things:
Take a fixed maximum number of parameters, and check them for null-ness before concatenating:
CREATE PROCEDURE SP_rptProvince2(a1 VARCHAR(45), a2 VARCHAR(45), ...)
...
IF a1 IS NOT NULL THEN
SET #strQuery = CONCAT(#strQuery, ' AND ', a2);
END IF;
If you need predetermined fields to which the criteria in the argument apply (like the e_Region parameter in your existing code), then you modify the CONCAT operation appropriately.
Possible invocation:
CALL SP_rptProvince2('''North''', 'column3 = ''South''')
Take a single parameter that is much bigger than just 45 characters, and simply append it to the query (assuming it is not null).
Clearly, this places the onus on the user to provide the correct SQL code.
Possible invocation:
CALL SP_rptProvince2('RegionName = ''North'' AND column3 = ''South''')
There's not a lot to choose between the two. Either can be made to work; neither is entirely satisfactory.
You might note that there was a need to protect the strings in the arguments with extra quotes; that is the sort of thing that makes this problematic.
I found a JSON-based approach which works with the latest MySQL/MariaDB systems. Check the link below (Original Author is Federico Razzoli): https://federico-razzoli.com/variable-number-of-parameters-and-optional-parameters-in-mysql-mariadb-procedures
Basically, you take a BLOB parameter which is actually a JSON object and then do JSON_UNQUOTE(JSON_EXTRACT(json object, key)) as appropriate.
Lifted an extract here:
CREATE FUNCTION table_exists(params BLOB)
RETURNS BOOL
NOT DETERMINISTIC
READS SQL DATA
COMMENT '
Return whether a table exists.
Parameters must be passed in a JSON document:
* schema (optional). : Schema that could contain the table.
By default, the schema containing this procedure.
* table : Name of the table to check.
'
BEGIN
DECLARE v_table VARCHAR(64)
DEFAULT JSON_UNQUOTE(JSON_EXTRACT(params, '$.table'));
DECLARE v_schema VARCHAR(64)
DEFAULT JSON_UNQUOTE(JSON_EXTRACT(params, '$.schema'));
IF v_schema IS NULL THEN
RETURN EXISTS (
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE
TABLE_SCHEMA = SCHEMA()
AND TABLE_NAME = v_table
);
ELSE
RETURN EXISTS (
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE
TABLE_SCHEMA = v_schema
AND TABLE_NAME = v_table
);
END IF;
END;

I am not able to determine the proper syntax for a DBeaver MySQL statement [duplicate]

How to declare a variable in mysql, so that my second query can use it?
I would like to write something like:
SET start = 1;
SET finish = 10;
SELECT * FROM places WHERE place BETWEEN start AND finish;
There are mainly three types of variables in MySQL:
User-defined variables (prefixed with #):
You can access any user-defined variable without declaring it or
initializing it. If you refer to a variable that has not been
initialized, it has a value of NULL and a type of string.
SELECT #var_any_var_name
You can initialize a variable using SET or SELECT statement:
SET #start = 1, #finish = 10;
or
SELECT #start := 1, #finish := 10;
SELECT * FROM places WHERE place BETWEEN #start AND #finish;
User variables can be assigned a value from a limited set of data
types: integer, decimal, floating-point, binary or nonbinary string,
or NULL value.
User-defined variables are session-specific. That is, a user
variable defined by one client cannot be seen or used by other
clients.
They can be used in SELECT queries using Advanced MySQL user variable techniques.
Local Variables (no prefix) :
Local variables needs to be declared using DECLARE before
accessing it.
They can be used as local variables and the input parameters
inside a stored procedure:
DELIMITER //
CREATE PROCEDURE sp_test(var1 INT)
BEGIN
DECLARE start INT unsigned DEFAULT 1;
DECLARE finish INT unsigned DEFAULT 10;
SELECT var1, start, finish;
SELECT * FROM places WHERE place BETWEEN start AND finish;
END; //
DELIMITER ;
CALL sp_test(5);
If the DEFAULT clause is missing, the initial value is NULL.
The scope of a local variable is the BEGIN ... END block within
which it is declared.
Server System Variables (prefixed with ##):
The MySQL server maintains many system variables configured to a default value.
They can be of type GLOBAL, SESSION or BOTH.
Global variables affect the overall operation of the server whereas session variables affect its operation for individual client connections.
To see the current values used by a running server, use the SHOW VARIABLES statement or SELECT ##var_name.
SHOW VARIABLES LIKE '%wait_timeout%';
SELECT ##sort_buffer_size;
They can be set at server startup using options on the command line or in an option file.
Most of them can be changed dynamically while the server is running using SET GLOBAL or SET SESSION:
-- Syntax to Set value to a Global variable:
SET GLOBAL sort_buffer_size=1000000;
SET ##global.sort_buffer_size=1000000;
-- Syntax to Set value to a Session variable:
SET sort_buffer_size=1000000;
SET SESSION sort_buffer_size=1000000;
SET ##sort_buffer_size=1000000;
SET ##local.sort_buffer_size=10000;
SET
SET #var_name = value; /* or */ SET #var_name := value;
both operators = and := are accepted
SELECT
SELECT col1, #var_name := col2 from tb_name WHERE "condition";
if multiple record sets found only the last value in col2 is kept (override);
SELECT col1, col2 INTO #var_name, col3 FROM ...
in this case the result of Select is not containing col2 values
Ex both methods used
-- TRIGGER_BEFORE_INSERT --- setting a column value from calculations
...
SELECT count(*) INTO #NR FROM a_table WHERE a_condition;
SET NEW.ord_col = IFNULL( #NR, 0 ) + 1;
...
Use set or select
SET #counter := 100;
SELECT #variable_name := value;
example :
SELECT #price := MAX(product.price)
FROM product
Different types of variable:
local variables (which are not prefixed by #) are strongly typed and scoped to the stored program block in which they are declared. Note that, as documented under DECLARE Syntax:
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements.
User variables (which are prefixed by #) are loosely typed and scoped to the session. Note that they neither need nor can be declared—just use them directly.
Therefore, if you are defining a stored program and actually do want a "local variable", you will need to drop the # character and ensure that your DECLARE statement is at the start of your program block. Otherwise, to use a "user variable", drop the DECLARE statement.
Furthermore, you will either need to surround your query in parentheses in order to execute it as a subquery:
SET #countTotal = (SELECT COUNT(*) FROM nGrams);
Or else, you could use SELECT ... INTO:
SELECT COUNT(*) INTO #countTotal FROM nGrams;
Declare:
SET #a = 1;
Usage:
INSERT INTO `t` (`c`) VALUES (#a);
For any person using #variable in concat_ws function to get concatenated values, don't forget to reinitialize it with empty value. Otherwise it can use old value for same session.
Set #Ids = '';
select
#Ids := concat_ws(',',#Ids,tbl.Id),
tbl.Col1,
...
from mytable tbl;
I would like to give my awnswer here so people can try, solution for MySql that i think is easyer to understand:
set #countVal = (select count(*) from STATION);
/**
499/2 = 249,5 -> 250 -- ceil
499/2 = 249,5 + 1 = 250,5 -- floor 250
500/2 = 250 -- ceil 250
= 250 + 1 = 251 -- flor 251
**/
set #ceilVal = ceil(#countVal/2);
set #floorVal = floor( (#countVal/2) + 1);
SELECT ROUND(AVG( latitude ),4) FROM
(SELECT #lineNum:= #lineNum + 1 as id,
lat_n as latitude
FROM STATION s, ( SELECT #lineNum :=0 ) pivot
ORDER BY lat_n) as a
WHERE id IN ( #ceilVal, #floorVal );
SET Value
declare #Regione int;
set #Regione=(select id from users
where id=1) ;
select #Regione ;

DBeaver declare statement for MySQL is failing [duplicate]

How to declare a variable in mysql, so that my second query can use it?
I would like to write something like:
SET start = 1;
SET finish = 10;
SELECT * FROM places WHERE place BETWEEN start AND finish;
There are mainly three types of variables in MySQL:
User-defined variables (prefixed with #):
You can access any user-defined variable without declaring it or
initializing it. If you refer to a variable that has not been
initialized, it has a value of NULL and a type of string.
SELECT #var_any_var_name
You can initialize a variable using SET or SELECT statement:
SET #start = 1, #finish = 10;
or
SELECT #start := 1, #finish := 10;
SELECT * FROM places WHERE place BETWEEN #start AND #finish;
User variables can be assigned a value from a limited set of data
types: integer, decimal, floating-point, binary or nonbinary string,
or NULL value.
User-defined variables are session-specific. That is, a user
variable defined by one client cannot be seen or used by other
clients.
They can be used in SELECT queries using Advanced MySQL user variable techniques.
Local Variables (no prefix) :
Local variables needs to be declared using DECLARE before
accessing it.
They can be used as local variables and the input parameters
inside a stored procedure:
DELIMITER //
CREATE PROCEDURE sp_test(var1 INT)
BEGIN
DECLARE start INT unsigned DEFAULT 1;
DECLARE finish INT unsigned DEFAULT 10;
SELECT var1, start, finish;
SELECT * FROM places WHERE place BETWEEN start AND finish;
END; //
DELIMITER ;
CALL sp_test(5);
If the DEFAULT clause is missing, the initial value is NULL.
The scope of a local variable is the BEGIN ... END block within
which it is declared.
Server System Variables (prefixed with ##):
The MySQL server maintains many system variables configured to a default value.
They can be of type GLOBAL, SESSION or BOTH.
Global variables affect the overall operation of the server whereas session variables affect its operation for individual client connections.
To see the current values used by a running server, use the SHOW VARIABLES statement or SELECT ##var_name.
SHOW VARIABLES LIKE '%wait_timeout%';
SELECT ##sort_buffer_size;
They can be set at server startup using options on the command line or in an option file.
Most of them can be changed dynamically while the server is running using SET GLOBAL or SET SESSION:
-- Syntax to Set value to a Global variable:
SET GLOBAL sort_buffer_size=1000000;
SET ##global.sort_buffer_size=1000000;
-- Syntax to Set value to a Session variable:
SET sort_buffer_size=1000000;
SET SESSION sort_buffer_size=1000000;
SET ##sort_buffer_size=1000000;
SET ##local.sort_buffer_size=10000;
SET
SET #var_name = value; /* or */ SET #var_name := value;
both operators = and := are accepted
SELECT
SELECT col1, #var_name := col2 from tb_name WHERE "condition";
if multiple record sets found only the last value in col2 is kept (override);
SELECT col1, col2 INTO #var_name, col3 FROM ...
in this case the result of Select is not containing col2 values
Ex both methods used
-- TRIGGER_BEFORE_INSERT --- setting a column value from calculations
...
SELECT count(*) INTO #NR FROM a_table WHERE a_condition;
SET NEW.ord_col = IFNULL( #NR, 0 ) + 1;
...
Use set or select
SET #counter := 100;
SELECT #variable_name := value;
example :
SELECT #price := MAX(product.price)
FROM product
Different types of variable:
local variables (which are not prefixed by #) are strongly typed and scoped to the stored program block in which they are declared. Note that, as documented under DECLARE Syntax:
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements.
User variables (which are prefixed by #) are loosely typed and scoped to the session. Note that they neither need nor can be declared—just use them directly.
Therefore, if you are defining a stored program and actually do want a "local variable", you will need to drop the # character and ensure that your DECLARE statement is at the start of your program block. Otherwise, to use a "user variable", drop the DECLARE statement.
Furthermore, you will either need to surround your query in parentheses in order to execute it as a subquery:
SET #countTotal = (SELECT COUNT(*) FROM nGrams);
Or else, you could use SELECT ... INTO:
SELECT COUNT(*) INTO #countTotal FROM nGrams;
Declare:
SET #a = 1;
Usage:
INSERT INTO `t` (`c`) VALUES (#a);
For any person using #variable in concat_ws function to get concatenated values, don't forget to reinitialize it with empty value. Otherwise it can use old value for same session.
Set #Ids = '';
select
#Ids := concat_ws(',',#Ids,tbl.Id),
tbl.Col1,
...
from mytable tbl;
I would like to give my awnswer here so people can try, solution for MySql that i think is easyer to understand:
set #countVal = (select count(*) from STATION);
/**
499/2 = 249,5 -> 250 -- ceil
499/2 = 249,5 + 1 = 250,5 -- floor 250
500/2 = 250 -- ceil 250
= 250 + 1 = 251 -- flor 251
**/
set #ceilVal = ceil(#countVal/2);
set #floorVal = floor( (#countVal/2) + 1);
SELECT ROUND(AVG( latitude ),4) FROM
(SELECT #lineNum:= #lineNum + 1 as id,
lat_n as latitude
FROM STATION s, ( SELECT #lineNum :=0 ) pivot
ORDER BY lat_n) as a
WHERE id IN ( #ceilVal, #floorVal );
SET Value
declare #Regione int;
set #Regione=(select id from users
where id=1) ;
select #Regione ;

Where is the error in this stored procedure

DELIMITER //
CREATE PROC InserimentoValori()
BEGIN
DECLARE #caratteri varchar(30);
set #caratteri = 'abcdefghijklmnopqrstuvwxyz',
DECLARE x INT DEFAULT 1;
WHILE x <=100 DO
INSERT INTO Persona(nome,cognome,eta) VALUES((SELECT #caratteri = substring(#caratteri +1),(SELECT #caratteri = sebstring(#caratteri +1),(SELECT floor(rand() * 99) AS randNum));
SET x = x+1;
END WHILE
END //
DELIMITER ;
I want to create a stored procedure that insert random values into the table.
Thanks
There are a couple of errors.
We don't "declare" user defined variables in MySQL. Just SET them.
If you want to DECLARE a variable within a procedure, that needs to be a procedure variable.
A user defined variable has a name that starts with the # character. A procedure variable cannot start with a # character.
So, a line like this is an error:
DECLARE #foo ...
If you want to use a user defined variable, remove that line. If you want to use a procedure variable, remove the # from the beginning of the variable name (and make that same change everywhere you want to reference the procedure variable foo.)
And SEBSTRING is not the name of a MySQL provided function.
Also, a boolean expression in a SELECT list of a query will return 0, 1 or NULL.
For example:
SELECT #caratteri = substring(#caratteri +1)
That expression is comparing the value on the left side of the = with the value on the right, and is going to return 1 if they are equal, or 0 if the aren't, or NULL if either of the values is NULL.
To perform an assignment to a user defined variable in a SELECT statement, use the Pascal-style := operator.
(If you meant to do an assignment, the design makes it look like you are gogin to lop off the first character each time through the loop; that's eventually going to be an empty string, if we loop enough times. You may want to think about leaving the string static. Consider incrementing integer values, and use those as arguments in SUBSTRING function. And you can use the MOD operator to get the integer value to "wrap".)

Determine what param to use in Select statement in a Stored Procedure

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.