DECLARE #bitVariable BIT NOT NULL -- how (MS SQL) [duplicate] - sql-server

In T-SQL, I declare a local variable for use with some query like so:
DECLARE #var_last datetime;
SET #var_last = (SELECT TOP(1) col_date FROM tbl_dates ORDER BY col_date);
In an application I'm testing, it would be an error for this query to return NULL, and it's desirable for the query to return a crash error if it were.
I'd like to set #var_last to be NOT NULL but the syntax...
DECLARE #var_last datetime NOT NULL;
...is invalid. I can write a simple check on the return of the query to see if it's NULL, and error if it is, but my question is, is it not possible to declare a local variable as NOT NULL?

That's right, according the documentation for the DECLARE #local_variable, available at: http://technet.microsoft.com/en-us/library/ms188927.aspx, it doesn't accept a NULL | NOT NULL parameter -- those are only valid for column definitions.
If you want to stop execution if you return a NULL, then test for NULL and, if it is, RAISERROR; see: http://technet.microsoft.com/en-us/library/ms178592.aspx.

You can do something like this ...
Using ISNULL()
SELECT TOP(1) #var_last = ISNULL(col_date,'19000101') --<-- Some default value
FROM tbl_dates
ORDER BY col_date;
Using COALESCE()
SELECT TOP(1) #var_last = COALESCE(col_date,'19000101') --<-- Some default value
FROM tbl_dates
ORDER BY col_date;

It is not possible to set a variable to NOT NULL because NULL and NOT NULL are states, not values (even tho you can set a variable to NULL which looks like you are setting a value but you are actually erasing the existing value).
NULL, by definition, means has no value.

Related

IsNull with Equal ¿What does this means?

I have a basic question of SQL
What does the IsNull()=0 means in this code?
As far as I know, = assigns a value, but in this case it is used inside a Where statement.
Hope somebody can explain it to me :)
Where vol.espe_codigo = matriz.espe_codigo
And IsNull(costo_gerencias.plde_codigo,0) = 0
isnull(firstvalue, secondvalue) tests if the value for firstvalue is NULL or not. When the value is not null than this value is returned, but when the value is null than the value of secondvalue is returned.
Examples :
declare #test varchar(100) = 'abc'
declare #test2 varchar(100) = '123'
isnull(#test, #test2) will return 'abc'
second example :
declare #test varchar(100) = null
declare #test2 varchar(100) = '123'
isnull(#test, #test2) will return '123'
third example :
declare #test varchar(100) = ''
declare #test2 varchar(100) = '123'
isnull(#test, #test2) will return ''
I use it most to check on varchar columns, since they may contain an empty string which is not the same as NULL, but in a DataGridView or TextBox you cannot see the difference.
It means that if costo_gerencias.plde_codigo is null, it will return 0 or whatever the second argument is to the ISNULL function. In this case, the WHERE clause is basically saying "where vol.espe_codigo is equal to matriz.espe_codigo and costo_gerencias.plde_codigo is null or equal to zero."
IsNull() is a function which takes two input values of any type; however the second must be implicitly convertible to the type to the 1st parameter. (See link)
The database engine evaluates the first parameter and if it's null, the system returns the second parameter. If the 1st parameter is not null, it returns the value of the first parameter.
So in your case the engine will return the value 0 if plde_codigo is null. If not null it returns the value of plde_codigo passed in.
This in turn means your result set will only contain records which have a NULL or 0 value in plde_Codigo; in addition to other limiting criteria.
It could also be written as:
(costo_gerencias.plde_codigo is NULL OR costo_gerencias.plde_codigo = 0)
or to be more database agnostic:
coalesce(costo_gerencias.plde_codigo,0)=0
But in this case plde_codigo must be numeric; whereas it could be text when using isNull()

Can I declare a local variable not null?

In T-SQL, I declare a local variable for use with some query like so:
DECLARE #var_last datetime;
SET #var_last = (SELECT TOP(1) col_date FROM tbl_dates ORDER BY col_date);
In an application I'm testing, it would be an error for this query to return NULL, and it's desirable for the query to return a crash error if it were.
I'd like to set #var_last to be NOT NULL but the syntax...
DECLARE #var_last datetime NOT NULL;
...is invalid. I can write a simple check on the return of the query to see if it's NULL, and error if it is, but my question is, is it not possible to declare a local variable as NOT NULL?
That's right, according the documentation for the DECLARE #local_variable, available at: http://technet.microsoft.com/en-us/library/ms188927.aspx, it doesn't accept a NULL | NOT NULL parameter -- those are only valid for column definitions.
If you want to stop execution if you return a NULL, then test for NULL and, if it is, RAISERROR; see: http://technet.microsoft.com/en-us/library/ms178592.aspx.
You can do something like this ...
Using ISNULL()
SELECT TOP(1) #var_last = ISNULL(col_date,'19000101') --<-- Some default value
FROM tbl_dates
ORDER BY col_date;
Using COALESCE()
SELECT TOP(1) #var_last = COALESCE(col_date,'19000101') --<-- Some default value
FROM tbl_dates
ORDER BY col_date;
It is not possible to set a variable to NOT NULL because NULL and NOT NULL are states, not values (even tho you can set a variable to NULL which looks like you are setting a value but you are actually erasing the existing value).
NULL, by definition, means has no value.

ISNULL what happens when the replacement value is NULL?

If the values in MyTable.MyColumn and #MyVar are NULL, what does the following statement return?
ISNULL(#MyVar, MyTable.MyColumn)
create table MyTable
(
MyColumn int
)
insert into MyTable default values
declare #MyVar int
select ISNULL(#MyVar, MyTable.MyColumn)
from MyTable
Result:
-----------
NULL
Others have explained what happens. Solutions in case you don't want those Nulls.
If the expression is in the SELECT list - and you don't want NULL to appear in the result, you can use the COALESCE() function which can take more than 2 parameters:
COALESCE(#MyVar, MyTable.MyColumn, another_value)
If you have it in a condition, like you mention in the comments:
WHERE MyTable.MyColumn = ISNULL(#MyVar, MyTable.MyColumn)
you can replace it with (assuming you want the condition to hold TRUE when #MyVar is null, no matter if MyTable.MyColumn is null or not):
WHERE (MyTable.MyColumn = #MyVar OR #MyVar IS NULL)
It will return NULL, of course. :) Quite easy to test too. What's the overall need for this? If you need to for example ensure that at least some value is returned, you have a few options. For example case:
SELECT CASE WHEN #MyVar IS NULL
THEN ISNULL(MyTable.MyColumn, 'replacementvalue')
ELSE #MyVar
END AS RESULT
FROM MyTable
We need to know more about the real issue here.
Try this :-)
select ISNULL(null,null)

Checking an input param if not Null and using it in where in SQL Server

What is the best way to include an input param in the WHERE clause but exclude it if it is null?
There are a number of ways I believe, but I can't seem to remember then.
Also could I use the COALESCE()? But I think this is only for SELECTing values?
Edit
To clarify, let's say a variable called #code ="1" then my where would be Where type='B' AND code = #code but if #code is null then I only want Where type='B' - notice the missing code = #code.
You can use IsNull
where some_column = IsNull(#yourvariable, 'valueifnull')
EDIT:
What you described in the comment can be done like:
where (#code is null or code = #code)
Here's another approach
SELECT * FROM Thingies WHERE ( #thingId IS NULL OR ThingID = #thingId )
How about
WHERE (Column1 = #Var1 OR #Var1 IS NULL)
AND (Column2 = #Var2 OR #Var2 IS NULL)
I’d like to suggest a solution which I found on another site:
SELECT * FROM Thingies
WHERE ThingID = isnull(#ThingId,ThingID)
With this solution if the user selects null for your parameter then your query will return all the rows as the result.
This question really helped me with a similar issue that had a few of us scratching our heads for a bit. I only write it up in case somebody else tries the same approach and cannot figure out why it does not work.
I was trying to only evaluate a part of a multipart WHERE clause if the #Parameter was not null. I tried to do this as below but always had no rows returned if #Parameter was null.
DECLARE #Parameter int = null;
SELECT * FROM TABLE
WHERE [AlternateID] is not null
AND (#Parameter is not null AND [AlternateID] = #Parameter)
I incorrectly thought that (#Parameter is not null AND [AlternateID] = #Parameter) would simply not form part of the full WHERE clause is #Parameter was null. However it was making the entire WHERE clause return false. The remedy was to add an OR 1=1 as below:
WHERE [AlternateID] is not null
AND (#Parameter is not null AND [AlternateID] = #Parameter OR 1=1)
Of course the approach outlined by Ali (not enough reputation to upvote) solves this more efficiently.
WHERE [AlternateID] is not null
AND [Partner_Customer_ID] = ISNULL(#Parameter, [Partner_Customer_ID])
You can use ISNULL(), or check for nulls explicitly as others have mentioned. This should be OK as long as you have no more than 1 or 2 optional input parameters. But if there are more parameters, this approach would be very inefficient as the indexes you create on those columns won't be used as you would expect. In such a case i would recommend you to use dynamic SQL. Here is an excellent article that explains why http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/
I think this will help
#id
#name
SELECT [Id],[Name] FROM [Person]
WHERE Id = #id and ISNULL(#name, Name)
This will allow you just ignore the Name condition if it is null

sqlmetal fails to extract udf with full-text

Error message:
Warning : SQM1014: Unable to extract function 'dbo.ProductFamilyIndex_EN' from SqlServer. Null or empty full-text predicate.
function defined as:
CREATE FUNCTION [dbo].[ProductFamilyIndex_EN]
(
#topn int,
#keywords nvarchar(4000)
)
RETURNS TABLE
AS
RETURN
(
select top (#topn) ProductFamilyID
from (
select pf.ProductFamilyID, t.[RANK] as _rank
from containstable(ProductFamily, (Name_EN), #keywords, LANGUAGE 'English', #topn) t
inner join ProductFamily pf on(pf.ProductFamilyID=t.[KEY])
union all
select p.ProductID as ProductFamilyID, t.[RANK] as _rank
from containstable(Product, (LongDescription_EN, ShortDescription_EN), #keywords, LANGUAGE 'English', #topn) t
inner join Product p on(p.ProductID=t.[KEY] and p.ProductFamilyID is null and p.Deleted is null)
) t
group by ProductFamilyID
order by max(_rank) desc
)
don't get confused by the union inside - that just means that a product without a family is a family on its own.
tried to give default values to the parameters:
#topn int = 1000,
#keywords nvarchar(4000) = 'test'
with the same result.
Using .NET 3.5 and sql2008.
As you mentioned, SQLMetal needs a return type.
Another way to solve this, is to explicitly set your default inside the stored procedure:
SET #topn = COALESCE(#topn, 1000)
Throw that before the SELECT statement to insure that any NULL parameters will return a valid value.
This is useful not only for SQLMetal, but for anyone who uses this function.
Reposting my own answer properly so I can close this thread.
Problem solved.
Apparently sqlmetal runs the function to figure out the return type, but insists on supplying null parameter instead of default, which seems like sqlmetal's bug.
Way to work around it is to declare return type explicitly:
alter function [dbo].[ProductFamilyIndex_EN] (#topn int, #keywords nvarchar(4000))
returns #t table (ProductFamilyID int not null)
as begin
...
return end

Resources