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

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)

Related

Oracle CASE missing right parenthesis for a "in" limit

I have a QRY im developing in Oracle for spotfire. In the where statement, I have a decision case statement and if its True, im trying to pass a list of items to match a column, below is what I have, but its throwing a missing right parenthesis error and I cannot determine why. In short, when a variable is determined True (in this case 9>8 for the example, I need it to result those items, else, result the entire column with no limits.
Note: This works fine when its only 1 item being passed, i.e. 'BOB' but as soon as its multiple, this error occurs.
and Column1 = (CASE When 9>8 Then ('BOB','TOM') Else Column1 END)
Case expressions are best avoided in the where clause. Instead, write the logic with AND and OR:
And (
(9>8 AND Column1 IN ('BOB','TOM'))
OR 9<=8 -- You say you check a variable here, don't forget to check for NULL
)
Oracle does not have a boolean type for use in SQL queries.
Instead, just use basic logic:
and ( (9 > 8 and Column1 in ('BOB','TOM')) or
9 <= 8
)

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

Why doesn't comparison work in CONVERT?

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.

Boolean expression as column value in transact sql

In most RDBMS:es, this work:
select (5 > 3)
and evaluates to true. It doesn't work in MS Transact SQL and the only workaround I've found is to write:
select case when 5 > 3 then 1 else 0 end
Which kind of sucks because it is much more verbose. Is there a better way to write the above kind of checks?
If the problem is arithmetic comparison:
select (5 - 3)
Then at the application level test for < or = or > 0.
You could write it as a scalar-valued function, but it will be very slow on large datasets.
If your program often requires such case constructs you could create your set of functions that will have user functions like Bool_IsGreater(left, right) that will return you your desired 0 or 1.
SQL Server doesn't support boolean value type anyway even for basic column use.
If you will need performance and those 5 and 3 values come naturally from some select query you might want to create a new column and set its value to 1 or 0 by trigger or something, which could help with performance.

Matching BIT to DATETIME in CASE statement

I'm attempting to create a T-SQL case statement to filter a query based on whether a field is NULL or if it contains a value. It would be simple if you could assign NULL or NOT NULL as the result of a case but that doesn't appear possible.
Here's the psuedocode:
WHERE DateColumn = CASE #BitInput
WHEN 0 THEN (all null dates)
WHEN 1 THEN (any non-null date)
WHEN NULL THEN (return all rows)
From my understanding, the WHEN 0 condition can be achieved by not providing a WHEN condition at all (to return a NULL value).
The WHEN 1 condition seems like it could use a wildcard character but I'm getting an error regarding type conversion. Assigning the column to itself fixes this.
I have no idea what to do for the WHEN NULL condition. My internal logic seems to think assigning the column to itself should solve this but it does not as stated above.
I have recreated this using dynamic SQL but for various reasons I'd prefer to have it created in the native code.
I'd appreciate any input. Thanks.
The CASE expression (as OMG Ponies said) is mixing and matching datatypes (as you spotted), in addition you can not compare to NULL using = or WHEN.
WHERE
(#BitInput = 0 AND DateColumn IS NULL)
OR
(#BitInput = 1 AND DateColumn IS NOT NULL)
OR
#BitInput IS NULL
You could probably write it using CASE but what you want is an OR really.
You can also use IF..ELSE or UNION ALL to separate the 3 cases