Using Logical Operators inside NULLIF() - sql

If, then how can we use logical operators inside the NULLIF() funtion in SQL. Suppose i have a variable #a with value 5. I want to return NULL value if
#a>3. (which it is)
DECLARE #a INT
SET #a = 5;
SELECT NUllIF(#a,>3) AS Logical
-- Error: Incorrect syntax near '>'.
SELECT NUllIF(#a,'>3') AS Logical
-- Error: Conversion failed when converting the varchar value '>200' to data type int.

DECLARE #a INT
SET #a = 5;
SELECT CASE WHEN ISNULL(#a,0)>3 THEN NULL ELSE #a END AS output
Was that what it was about?

Use CASE
SELECT CASE WHEN #a<=3 THEN #a END AS Logical

Since you are using SQL Server 2016, you can use IIF function.
DECLARE #a AS INT = 5;
SELECT IIF(#a > 3, NULL, #a) AS Logical

Related

Data type error when passing dynamic column names into SQL Server

I've run into an issue while executing a stored procedure from VBA: I want to pass in a column name as a string for the parameter, and then use a case statement to select the actual column name in the data.
This query works fine when the column name (#FACTOR) i'm passing through is an integer, but not when it's a varchar. I get a conversion error:
Error converting data type nvarchar to float.
Here's my code:
WITH T0 AS (
SELECT DISTINCT
CASE #FACTOR
WHEN 'DRVREC' THEN DRIVINGRECORD --OK
WHEN 'POAGE' THEN POAGE
WHEN 'ANNUALKM' THEN AMC_VH_ANNL_KM
WHEN 'DAILYKM' THEN AMC_VH_KM_TO_WRK
WHEN 'RATETERR' THEN AMC_VH_RATE_TERR --OK
WHEN 'BROKERNAME' THEN MASTERBROKER_NAME
WHEN 'DRVCLASS' THEN DRIVINGCLASS -- OK
WHEN 'VEHAGE' THEN VEH_AGE -- OK
WHEN 'YEARSLIC' THEN YRSLICENSE
WHEN 'COVERAGECODE' THEN COVERAGECODE
ELSE NULL END AS FACTOR FROM DBO.Automation_Data
),
...
...
Or perhaps the example below is more concise:
DECLARE #FACTOR varchar(50)
SELECT #FACTOR = 'NOT_A_VARCHAR'
SELECT CASE #FACTOR
WHEN 'A_VARCHAR' THEN COLUMNNAME1
WHEN 'NOT_A_VARCHAR' THEN COLUMNNAME2
ELSE NULL END AS FACTOR FROM dbo.myTable
^ This would work, but if #FACTOR = 'A_VARCHAR' then i get the error.
Thanks in advance!
UPDATE **********************************:
It appears to be an issue with the case statement itself?
When I only have the varchar option in my case statement, the query runs. When I un-comment the second part of the case statement I get the error.
DECLARE #FACTOR varchar(50)
SELECT #FACTOR = 'A_VARCHAR'
SELECT CASE #FACTOR
WHEN 'A_VARCHAR' THEN COLUMNNAME1
--WHEN 'NOT_A_VARCHAR' THEN COLUMNNAME2 ELSE NULL
END AS FACTOR FROM dbo.myTable
When you are selecting from multiple columns as a single column like you are doing, SQL returns the result as the highest precedence type. Same goes with coalesce etc. when a single result is to be returned from multiple data types.
If you try the code below for example, 3rd select will return the error you're getting, as it tries to convert abc to int (higher precedence). If you set #V to '123', error will go away, as the convert from '123' to int/float works. When you check the 'BaseType' of the result, you can see it shows the highest precedence data type of the mixed types.
DECLARE #F int = 1 --if you use float here error message will show ...'abc' to data type float.
DECLARE #V varchar(5) = 'abc'
DECLARE #O varchar = '1'
SELECT CASE WHEN #O = '1' THEN #F ELSE #V END --no error
SELECT SQL_VARIANT_PROPERTY((SELECT CASE WHEN #O = '1' THEN #F ELSE #V END), 'BaseType') --int/float
SET #O = '2'
SELECT CASE WHEN #O = '1' THEN #F ELSE #V END --error: Conversion failed when converting the varchar value 'abc' to data type int.
When you converted all your selects to nvarchar, nvarchar became the highest precedence data type, so it worked. But if you know some of your columns are float and some of them nvarchar, you only need to convert float columns to nvarchar. So this will work as well:
SET #O = '2'
SELECT CASE WHEN #O = '1' THEN CONVERT(NVARCHAR(5), #F) ELSE #V END
See SQL Data Type Precedence

Can You Assign a Function Call to a Local Var in SQL Server's Where Clause

In SQL Server 2012 (or 2014), is it possible to convert a select statement like
... where S.getAge(Handle) >= #ageMin and S.getAge(Handle) <= #ageMax
into something like (in pseudo-code)
... where {set #a = S.getAge(Handle)} and #a >= #ageMin and #a <= #ageMax
SQL Expert Itzik Ben-Gan describes the Logical Query Processing Phases in his book Inside Microsoft SQL Server 2008: T-SQL Querying.
The correct order is as follows:
1. FROM
2. ON
3. OUTER
4. WHERE
5. GROUP BY
6. CUBE | ROLLUP
7. HAVING
8. SELECT
9. DISTINCT
10. ORDER BY
11. TOP
Assignment of a variable is always done in the SELECT part of the statement before the FROM clause.
However, SQL Server allows you to do stuff that you should not TRY.
Lets do a test case. A simple table that counts from 1 to 10 in tempdb and a simple scalar function that takes the number and multiples it by 10 to get the age.
This has some similarities to your example.
-- Use temp db
USE TEMPDB;
GO
-- Create simple table
CREATE TABLE T1
( MYID INT IDENTITY (1,1) );
GO
-- Add 10 records
INSERT INTO T1 DEFAULT VALUES;
GO 10
-- Create a scalar valued function
CREATE FUNCTION GETAGE (#INDEX INT)
RETURNS INT
AS
BEGIN
RETURN (#INDEX * 10);
END
GO
-- Returns 10
DECLARE #A INT;
SELECT #A = DBO.GETAGE(1);
PRINT #A
Here is an example of what you are trying to do below.
The where clause is step 4 in the logical evaluation. It either filters records in or out of the final result. We do have an assignment in the expressions in the WHERE clause. However, expressions should result in TRUE, FALSE or UNKNOWN (NULL).
What does assignment return?
I can only guess not TRUE since a AND between the expressions shows no records. A OR between the expressions shows the records.
-- OR displays 4 to 8, AND = empty result set
DECLARE #A INT = 0;
SELECT MYID FROM TBL1
WHERE
(#A = DBO.GETAGE(MYID)) OR
(DBO.GETAGE(MYID) > 30 AND DBO.GETAGE(MYID) < 90);
PRINT #A;
Last but not least, what are you trying to do?
This code only returns the last assignment.
-- Only displays last assignment
DECLARE #A INT = 0;
SELECT #A = DBO.GETAGE(MYID) FROM TBL1
WHERE (DBO.GETAGE(MYID) > 30) AND (DBO.GETAGE(MYID) < 90);
PRINT #A;
This code return a comma delimited list.
-- Comma delimited list
DECLARE #A VARCHAR(MAX) = '';
SELECT #A += STR(DBO.GETAGE(MYID), 2, 0) + ', ' FROM TBL1
WHERE (DBO.GETAGE(MYID) > 30 AND DBO.GETAGE(MYID) < 90);
IF LEN(#A) > 0 SET #A = SUBSTRING(#A, 1, LEN(#A) - 1);
PRINT #A;

Why does condition #parameter like (condition) not return results, while replacing the parameter with a literal does?

I was trying this in mssql2008:
declare #test nvarchar
set #test = '12345'
select 'true' where #test like '%3%' -- no results, condition fails
select 'true' where '12345' like '%3%' -- returns true, condition passes
Can someone please explain to me why the first select statement does not return any result?
Change
declare #test nvarchar
to
declare #test nvarchar(10)
SQL Fiddle DEMO
So to answer your question, from nchar and nvarchar (Transact-SQL)
When n is not specified in a data definition or variable declaration
statement, the default length is 1. When n is not specified with the
CAST function, the default length is 30.
This happends because #test nvarchar is initialised with a size of 1 i.e. it only contains '1' from the your set statement.
If you change the declare statement to #test nvarchar(5), it'll work.

casting to Integer is not working properly?

execute these and check the result why is it so ?
declare #a decimal(8,3) =235.363
declare #b int =1
select case #b
when 1 then cast(#a as int)
when 2 then CAST(#a as decimal(8,3))
end
Result : 235.000
declare #a decimal(8,3) =235.363
declare #b int =1
select case #b
when 1 then cast(#a as int)
--when 2 then CAST(#a as decimal(8,3))
end
Result : 235
declare #a decimal(8,3) =235.363
declare #b int =1
select case #b
when 1 then cast(#a as tinyint)
when 2 then CAST(#a as float)
end
Result : 235
What you see is not what you get.
For the column type, SQL Server picks the correct, more wide type (float over tinyint, decimal over int). You can verify that by doing select into instead of just select.
It's just the display rules that are different.
When the selected column type is float, you don't see the trailing .000 when there is no fractional part.
For decimal with explicit positions set, such as decimal(8,3), you will see the trailing .000 even if there's no fractional part. If you remove the specifier and only leave decimal as the column type, the .000 will disappear.
All that does not affect the actual column type, which is always the widest one.
This behaviour is documented in the BOL entry for CASE
Return Types
Returns the highest precedence type from the set of types in
result_expressions and the optional else_result_expression. For more
information, see Data Type Precedence (Transact-SQL).
If you follow the link to data type precedence you will see that float has higher precedence than decimal which in turn has higher precedence than tinyint so this behaviour is expected.
Probably cast operation will cast all the options to a bigger type.
From MSDN:
The data types of input_expression and each when_expression must be
the same or must be an implicit conversion.
http://msdn.microsoft.com/en-us/library/ms181765.aspx
Casting to Integer is not working properly.
Your statement is not correct!
In CASE statement, you can only return one type of data, so according to your statement you can return either INT or decimal(8,3), since your case statement has decimal(8,3) so here INT data is implicitly converted to decimal! Please see below example:, always try to use same return type in CASE statement to get proper and expected result, thanks.
1.
select case #b
when 1 then CAST(#a as int) -- return type INT
when 2 then CAST(#a as int) -- return type INT
end
2.
select case #b
when 1 then CAST(#a as int) -- return type INT and then converted to decimal(8,3)
when 2 then CAST(#a as decimal(8,3)) -- return type return type INT
end

SQL: Get value at index in binary value

Is there a SQL command that could be used in a query, stored procedure, function, that would work against a Binary Type similar to the following C# code?
if (someBinaryArray[index] == 0) {
...
I'm wanting to check if an index of a position in the binary is a certain value instead of pulling the entire array down and doing the comparison?
You can use Substring(), according to the documentation it works with binary columns:
SELECT *
FROM Table
WHERE Substring(column, index, length) = 'blah'
If you really wanted to check for a null (as in your example)... you could do this:
SELECT *
FROM table
WHERE SUBSTRING(column, 3, 1) = CHAR(0)
If you work on MSSQL Server, you can use the READTEXT command
CREATE TABLE #t (b varbinary(1))
DECLARE #ptrval varbinary(16)
SELECT #ptrval = TEXTPTR(mybinarraycolumn)
FROM mytable WHERE pk = #pk
INSERT INTO #t (b)
READTEXT pub_info.pr_info #ptrval #index 1
DECLARE #b varbinary(1)
SELECT #b = b FROM #t