Why doesn't comparison work in CONVERT? - sql

Is it possible to use a comparison operator in a CONVERT or CAST function?
I've got a statement that looks like this:
SELECT
...
CASE field
WHEN 'Y' THEN 1 # If Y then True
ELSE 0 # Anything else is False
END
...
FROM ...
A similar thing happens for a few fields, so I would like to change it to a shorter version:
SELECT
...
CONVERT(BIT, field = 'Y')
...
FROM ...
But MSSQL is giving an error Incorrect syntax near '='.
My interpretation of the help is that it should work:
CONVERT ( data_type [ ( length ) ] , expression [ , style ] )
expression: expression { binary_operator } expression
binary_operator: Is an operator that defines the way two expressions are combined to yield a single result. binary_operator can be an arithmetic operator, the assignment operator (=), a bitwise operator, a comparison operator, a logical operator, the string concatenation operator (+), or a unary operator.
comparison operator: ( = | > | < | >= | <= | <> | != | !< | !> )
I ran a few tests and got these results:
SELECT CONVERT(BIT, 0) // 0
SELECT CONVERT(BIT, 1) // 1
SELECT CONVERT(BIT, 1+2) // 1
SELECT CONVERT(BIT, 1=2) // Error
SELECT CONVERT(BIT, (1=2)) // Error
SELECT CONVERT(BIT, (1)=(2)) // Error

I think you are misinterpreting the documentation for CONVERT. There is nothing in the documentation for CONVERT that states it will handle an expression that makes use of the comparison operators, only that it accepts an expression. It turns out that CONVERT does not handle every valid SQL expression. At the very least it cannot handle the results of an expression that uses a comparison operator.
If you check the documentation for Operators, you'll see that the comparison operators (which is what you want = to be, in this case) return a Boolean data type, and are used in WHERE clauses and control-of-flow statements. From the documentation for Operators:
The result of a comparison operator has the Boolean data type, which has three values:
TRUE, FALSE, and UNKNOWN. Expressions that return a Boolean data type are known as
Boolean expressions.
Unlike other SQL Server data types, a Boolean data type cannot be
specified as the data type of a table column or variable, and cannot
be returned in a result set.
...
Expressions with Boolean data types are used in the WHERE clause to
filter the rows that qualify for the search conditions and in
control-of-flow language statements such as IF and WHILE...
That helps to explain why SQL like SELECT 1=2 is invalid SQL, because it would create a result set with a Boolean data type, which the documentation says is not allowed. That also explains why the CASE WHEN construct is necessary, because it can evaluate the comparison operators and return a single value of a data type that SQL Server can return in a result set.
Furthermore, if you look at the documentation for CONVERT, you'll see that Boolean is not supported in either CAST or CONVERT (see the table towards the middle of the page, there is no Boolean data type in there).
For your purposes, I think you're stuck using CASE WHEN. If it helps you can write it all on one line:
CASE WHEN field = 'Y' THEN 1 ELSE 0 END
Alternatively, you could create a UDF to handle the CASE expression (something like dbo.func_DoCase(field, 'Y', 1, 0)), but personally I would just stick with CASE WHEN.

Related

How to query empty string in postgresql?

I have table, in which a column has empty fields.when i try to run simple query like below it is not
returning the data.
select * from table1 where "colunm1" = ''
But below two queries returns data
1,
select * from table1
where coalesce("colunm1", '') = ''
2,
select * from table1
where "colunm1" is null
Can someone tell me the reason?
TIA
You have describe the behavior of a column that is NULL. NULL is not the same as an empty string.
It fails any equality comparison. However, you can use is null or (less preferentially) coalesce().
The only database that treats an empty string like a NULL value, is Oracle.
Logically, for a DBMS, that would be wrong.
Relational DBMSs are all about :
set theory
Boolean algebra
A NULL value is a value that we don't know. A string literal of '' is a string whose value we know. It is a string with no characters, with a length of 0. We don't know of a NULL as a string how long it is, how many and, if any, which, characters it contains.
So it is only logical that:
the comparison '' = '' will evaluate to TRUE
the comparison NULL = NULL will evaluate to FALSE , as any comparison with a NULL value will evaluate to FALSE.
And functions like COALESCE() or NVL(), IFNULL(), ISNULL() will return the first parameter if it does not contain a NULL value. That is consistent.
Except in Oracle

why 'select (0 < 1)' does not work in Sql Server?

If I let MySQL execute SELECT (0 < 1), it return 1; But if I run this select statement with SQL Server, it give me an error:
Incorrect syntax near '<'.
I also have tested other operator like != and <, and get the same error. I'm confused. '0 < 1' is an expression, why can't SQL Server evaluate it?
This behavior is by design:
Unlike other SQL Server data types, a Boolean data type cannot be
specified as the data type of a table column or variable, and cannot
be returned in a result set.
[...]
Expressions with Boolean data types are used in the WHERE clause to
filter the rows that qualify for the search conditions and in
control-of-flow language statements such as IF and WHILE
So Boolean datatype exists, you just cannot use it outside WHERE clause (etc).
The correct SQL Server equivalent of MySQL SELECT x < 1 (which returns 0, 1 or NULL) would be:
SELECT CASE
WHEN x < 1 THEN 1
WHEN NOT (x < 1) THEN 0
ELSE NULL -- you can omit this line
END
Finally, LEN(NULL) is NULL and (generally speaking) any operation on NULL yields NULL. So the condition IF LEN(NULL) < 1 will not execute, neither will IF LEN(NULL) >= 1.
MS SQL doesn't have a boolean type. It supports boolean expressions, but those cannot be values in variables or result sets.
The best you can do is something like
select case when 0 < 1 then 0 else 1 end
The result set will have a normal integer (the bit type is sometimes used to represent true/false values, but it's just a number with possible values of 1 and 0).
I'm confused. '0 < 1' is an expression, why can't SQL Server evaluate it?
It sort of is and sort of isn't. It's a predicate, and SQL Server treats predicates differently from other expressions which produce values.
SQL Server doesn't have a user-visible boolean data type so you cannot write an expression that produces a value of this non-existent data type.
You can only use predicates in specific positions, such as the WHERE clause, ON clauses, WHEN clauses (part of a CASE expression) and CHECK constraints (there are others)

SQL Server boolean operators

I know that SQL Server does not have boolean data type and your best option is to use BIT data type.
My question is to what boolean expressions evaluate. For example if I have the statement
expr1 AND expr2
and if expr1 is true and expr2 is false, do they internally evaluate to BITs with values 1 and 0? And then the AND operator checks for BITs?
I think this is not the case because then the following should work:
select 1 where 1 and 0
So does sql server internally have a boolean data type?
The following work
select 1 where 1 = 0
select 1 where 1 = 0 and 0 = 0
but this
select 1 where 1 and 0
reports
Msg 4145, Level 15, State 1, Line 1
An expression of non-boolean type specified in a context where a condition is expected, near 'and'.
which means that internally sql server handles the expressions as booleans, but why don't have access to that data type.
SQL Server does have a Boolean data type. You can open the Logical Operators (Transact-SQL) manual page and find the following statement:
Logical operators test for the truth of some condition. Logical operators, like comparison operators, return a Boolean data type with a value of TRUE, FALSE, or UNKNOWN.
It's just that you can't use this type in the same way you can use other Transact-SQL data types. For instance, you can't declare boolean variables or arguments, add boolean columns to tables, cast to/from a boolean. But you can have boolean expressions and use them in contexts where they are required (WHERE, ON, check constraints…). You can also apply boolean operators to those expressions: AND, NOT et al. (Operators like <, =, LIKE and other can also be considered boolean, in the sense that they return boolean results, but their operands are actually never booleans.)
So, to summarise, there is a boolean type in SQL Server but its use is limited, as described above. Why? My answer may be a silly one, sorry, but that's one that I'm satisfied with: this is the way they chose it to be.
Logical operators results in true or false. So in your example you get a result if expr1 and expr2 is true. To check if its true or not is the operation you do for each expression.
So you compare e.g. a column against something like a bit value column_bit = 0 and this results in true or false.
If your expr1 is true and expr2 is false your result is false for the logical AND operator.
Edit:
Your select 1 where 1 and 0 can't work because you don't use a compare operator. 1=1 AND 0=0 works e.g. but its nonsense :)

SQL CASE in Query - Odd behavior

Using a Case Statement in a query seems to work fine as long as the only case you want to match to is a string. But if you want to put ">" greater than (date or number), etc, SSMS automatically adds apostrophes around your statement (below) as if it were a string.
How can I get it to accept "greater than date" or "greater than number", etc??
There are two types of CASE expression:
The simple CASE expression compares an expression to a set of simple expressions to determine the result.
The searched CASE expression evaluates a set of Boolean expressions to determine the result.
You want a searched CASE expression. This means that the WHEN should come immediately after the CASE keyword.
CASE WHEN SoldDate <= SubjectDate THEN ...
There are two types of CASE expressions (from msdn):
A Simple CASE compares the specified expression for EQUIVALENCY ONLY
SELECT FieldName CASE WHEN 'Blah' THEN 'Foo' ELSE 'Bah' END
A Searched CASE can do inequalities too but has more verbose syntax:
SELECT CASE WHEN FieldName >= 'Blah' THEN 'Foo' ELSE 'Bah' END
You are trying to use the Simple syntax and need to use the Searched syntax by explicitly writing out the fieldname and comparison for each evaluation.
Your CASE statement syntax is incorrect. WHEN should come directly after CASE
This:
CASE SoldDate WHEN ...
Should be this:
CASE WHEN SoldDate <= SubjectDate THEN SoldFor ELSE EstSalePrice END
Additional Information
Take a look at the MSDN docs for additional examples of CASE syntax.

Sql Server: CASE Statement does unexpected behavior when comparing to NULL

Given:
The following Select statement:
select case NULL
when NULL then 0
else 1
end
Problem:
I'm expecting this to return 0 but instead it returns 1. What gives?
Generally speaking, NULL is not something you should attempt to compare for equality, which is what a case statement does. You can use "Is NULL" to test for it. There is no expectation that NULL != NULL or that NULL = NULL. It's an indeterminate, undefined value, not a hard constant.
-- To encompass questions in the comments --
If you need to retrieve a value when you may encounter a NULL column, try this instead:
Case
When SomeColumn IS NULL
Then 0
Else 1
End
I believe that should work. As far as your original post is concerned:
Select Case NULL
When NULL then 0 // Checks for NULL = NULL
else 1 // NULL = NULL is not true (technically, undefined), else happens
end
The trouble is that your Case select automatically attempts to use equality operations. That simply doesn't work with NULL.
I was going to add this as a comment to Aaron's answer, but it was getting too long, so I'll add it as another (part of the) answer.
The CASE statement actually has two distinct modes, simple and searched.
From BOL:
The CASE expression has two formats:
The simple CASE expression compares an expression to a set of simple expressions to determine the result.
The searched CASE expression evaluates a set of Boolean expressions to determine the result.
When the simple CASE (your example) does what it describes as comparison it does an equality comparison - i.e. =
This is clarified in the later documentation:
The simple CASE expression operates by comparing the first expression
to the expression in each WHEN clause for equivalency. If these
expressions are equivalent, the expression in the THEN clause will be
returned.
Allows only an equality check.
Because anything = NULL is always false in ANSI SQL (and if you didn't know this, you need to read up on NULLs in SQL more generally, particularly also with the behavior in the other searched comparison - WHERE x IN (a, b, c)), you cannot use NULL in a simple case and have it ever be compared to a value, with a NULL either in the initial expression or in the list of expressions to be compared against.
If you want to check for NULL, you will have to use an IF/ELSE construct or the searched CASE with a full expression.
I agree that it's kind of unfortunate there is no version which supports an IS comparison to make it easier to write:
select case colname
when IS NULL then 0
else 1
end
Which would make writing certain long CASE statements easier:
select case colname
when IS NULL then ''
when 1 then 'a'
when 2 then 'b'
when 3 then 'c'
when 4 then 'd'
else 'z'
end
But that's just wishful thinking...
An option is to use ISNULL or COALESCE:
select case COALESCE(colname, 999999) -- 999999 is some value never used
when 999999 then ''
when 1 then 'a'
when 2 then 'b'
when 3 then 'c'
when 4 then 'd'
else 'z'
end
But it isn't always a great option.
In addition to the other answers, you need to change the syntax for CASE slightly to do this:
SELECT CASE
WHEN NULL IS NULL THEN 0
ELSE 1
END;
Using the value in your syntax implicitly uses an equals comparison. NULL is unknown, and so is NULL = NULL, so with your current code you will always get zero 1 (geez I did it too).
To get the behavior you want, you can use SET ANSI_NULLS ON; however note that this can change other code in ways you may not be able to predict, and the setting is deprecated - so it will stop working at all in a future version of SQL Server (see this SQL Server 2008 doc).
You need to use the IS NULL operator. Standard comparison operators do not work with NULL.
Check out these MSDN articles about Null that may be useful:
IS [NOT] NULL (Transact-SQL)
Null Values