Unexpected BLOB results with MySQL testing NULL variable with IFNULL, COALESCE - mysql

In trying to test whether a variable has been defined, I discovered that the IF, IFNULL, and COALESCE statements return simply BLOB rather than the value I expected when (a) the variable has not been defined or (b) it has been explicitly set to NULL before being assigned a value in the session. I've verified this in MySQL versions 5.7 and 8.0.
SELECT IF(#p IS NULL, 'is null', 'not null'); # 'is null'
SELECT IF(#p IS NULL, 'is null', #p); # BLOB
SELECT IFNULL(#p, 'is null'); # BLOB
SELECT COALESCE(#p, 'is null'); # BLOB
The first statement acts as I expected, but the others return BLOB rather than 'is null'. The behavior is the same if preceded by SET #p = NULL.
On the other hand, if you do any of these, the above statements will all return 'is null', that is, they act as expected with a null value.
SET #p = NULL + 1 rather than SET #p = NULL before testing.
SET #p = 5; SET #p = NULL; That is, first set a non-null value, then set to null
SELECT COALESCE(#p+1, 'is null') # use expression #p+1 instead of #p.
Presumably, these three somehow set a type for NULL. In any case, an undefined variable or variable only defined as NULL have a different kind of NULL than those with a history of typing (?).
What is the underlying principle that explains this behavior? Is it simply an untyped NULL acts differently than a typed NULL, and those statements don't work with untyped ones?
Note: I know that that a workaround for this in a procedure, in order to detect undefined variables, can be
IF #p IS NULL
SET #p = default_value
END IF;
and it looks as if I can also use COALESCE(#p+1,default_value). But I'm interested in the explanation for why this is needed. Thanks.

Related

MySQL triggers integer variable

I want to do something like this:
DECLARE VAR_NAME INT DEFAULT 0;
IF NEW.field_name != NULL THEN
SET VAR_NAME := 8;
END IF;
IF NEW.field_name = NULL THEN
SET VAR_NAME := 1;
END IF;
UPDATE table_name SET column_name = column_name + VAR_NAME WHERE table_id = NEW.given_id;
I have a trigger for when inserting a new value:
I declare a variable, I change its value based on some conditions and then I update a table by adding this value to the current value of a specific column where the condition is met 'table_id = NEW.given_id'
Even I don't get errors the desired result is not happening.
Right, as the comments indicate, you can't check for NULL with normal equality operators. The way that I understand this is that nothing is equal to, less than, or greater than, etc, NULL, as NULL is literally 'no value'.
You must instead use IS NULL or IS NOT NULL to check for NULL.
This link goes into further detail:
http://dev.mysql.com/doc/refman/5.7/en/working-with-null.html

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.

Multiple Variable If Statement

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 )
...

Optional parameters in SQL Server stored procedure

I'm writing some stored procedures in SQL Server 2008. Is the concept of optional input parameters possible here?
I suppose I could always pass in NULL for parameters I don't want to use, check the value in the stored procedure, and then take things from there, but I was interested if the concept is available here.
You can declare it like this:
CREATE PROCEDURE MyProcName
#Parameter1 INT = 1,
#Parameter2 VARCHAR (100) = 'StringValue',
#Parameter3 VARCHAR (100) = NULL
AS
/* Check for the NULL / default value (indicating nothing was passed) */
if (#Parameter3 IS NULL)
BEGIN
/* Whatever code you desire for a missing parameter */
INSERT INTO ........
END
/* And use it in the query as so */
SELECT *
FROM Table
WHERE Column = #Parameter
Yes, it is. Declare the parameter as so:
#Sort varchar(50) = NULL
Now you don't even have to pass the parameter in. It will default to NULL (or whatever you choose to default to).
In SQL Server 2014 and above at least, you can set a default, and it will take that and not error when you do not pass that parameter.
Partial example: the third parameter is added as optional. Execution (exec) of the actual procedure with only the first two parameters worked fine.
exec getlist 47,1,0
create procedure getlist
#convId int,
#SortOrder int,
#contestantsOnly bit = 0
as
The default mentioned in previous answers only works for simple cases. In more complicated cases, I use an IF clause near the beginning of the stored procedure to provide a value, if the parameter is NULL or empty and calculations are required.
I often use optional parameters in the WHERE clause, and discovered that SQL does not short circuit logic, so use a CASE statement to make sure not to try to evaluate NULL or empty dates or unique identifiers, like so:
CREATE Procedure ActivityReport
(
#FromDate varchar(50) = NULL,
#ToDate varchar(50) = NULL
)
AS
SET ARITHABORT ON
IF #ToDate IS NULL OR #ToDate = '' BEGIN
SET #ToDate = CONVERT(varchar, GETDATE(), 101)
END
SELECT ActivityDate, Details
FROM Activity
WHERE
1 = CASE
WHEN #FromDate IS NULL THEN 1
WHEN #FromDate = '' THEN 1
WHEN ActivityDate >= #FromDate AND ActivityDate < DATEADD(DD,1,#ToDate) THEN 1
ELSE 0
END

In MySQL stored procedures check if a local variable is null

With the following example stored procedure
DECLARE Variable DOUBLE;
DECLARE Variable2 DOUBLE;
SELECT Something FROM Somewhere INTO Variable;
SELECT Something FROM SomewhereElse INTO Variable 2;
SELECT (Variable + Variable2);
If either Variable or Variable2 are NULL then the final SELECT will return null, what I would like is that if they are null they should be converted into 0.00 before the final SELECT, how do you do this? I already tried adding
SELECT 0.00 INTO Variable WHERE Variable IS NULL;
just above the final select but that didn't work.
SELECT COALESCE(variable, 0) + COALESCE(variable2, 0)
if you want each variable null converted to 0 use the solution posted by Quassnoi
SELECT COALESCE(variable, 0) + COALESCE(variable2, 0)
if you want to have 0 if either variable is null then use
SELECT COALESCE(variable + variable2, 0)
Quassnoi's correct, but it's even simpler (and a bit faster) to just coalesce the result:
SELECT coalesce( Variable + Variable2, 0 );
This works because for almost all operators, any null operand will make the operation null:
select 1 + null ; -- null
select null + 1 ; -- null
select null + null ; -- null
In the expression: SELECT coalesce( Variable + Variable2, 0 ); the result of the addition expression Variable + Variable2 is coalesce first argument; if that's null, coalesce returns its second argument, 0, otherwise it returns the (non-null) value of its first argument, which is the sum we want.
The few operators and functions that don't return null for a null operand are those designed to work on nulls: coalesce, is null, is not null.
As kristof notes below, the value of the select expression is different using Quassnoi's expression, if only one variable is null: his will return the value of the non-null variable if one is null; mine will return zero if either variable is null. Which is "right" depends on your intent.