How SQL String Comparison Works? - sql

I had a condition written like
IF(LEN(#strData) > 3 OR #strData > '255') BEGIN
// Some Condition
END
This is written in a sp which i come across written by someone.
First Condition is clear if LEN > 3 its coming true for that condition.
But > '255' what does it mean ?
I passed random values like
#strData = 'add' Result true
#strData = 'a' Result true
#strData = '12hhd' Result false
I didn't understand what way it behaves.
That query is not commented why fellow developer writes that line.
In SQL String Comparison how it will work..
Please some make me clear.
UPDATE :
I need that same condition in C# for some purpose

In SQL Server a string comparison is done in alphabetical order. That is "allan" is greater than "alan" because alphabetically "alan" comes before "allan". So, numbers are treated the same when doing string comparison, they are treated in alphabetical order...so, '2' is greater than '12'...surprising, huh? Well, alphabetical string comparisons are done from left to right hence '2' is greater than '12'.
Now, in C#, there's absolutely no difference it behaves exactly the same as sql. To reinforce any possible doubts you might have...you can easily test it....
SQL
if '2' > '12'
select '2 > 12';
else
select '2 < 12';
C# Console App
if ("2".CompareTo("12") < 0 )
Console.WriteLine("2 is less than 12");
else if ("2".CompareTo("12") > 0)
Console.WriteLine("2 is greater than 12");
else
Console.WriteLine("2 is equal to 12");
Hope it makes sense for you

Its a simple comaprision between two strings.
An SQL string comparision works like so:
Compare 'a' with '255' for '>'
if length(a) < length(b)
pad a with spaces to be same length as b;
for x = 0 to length(a)
if a(x) < b(x) return false;
if a(x) > b(x) return true;
return false;
In the case of your " 'a' > '255' "
the ASCII/utf-8 letter 'a' is greater than the character '2' so it returns true on the first character comparision,

Related

How can I include exceptions in my CASE WHEN Statements in SQL Server?

I am working on a project in SQL Server Management Studio (v18.10), and basically what I need is exception handling for some of our rules. We have functions in place to do some other calculations based on if it is an even or odd number, but because there are "exceptions" I need to be able to handle those as well. The numbers are stored as text because they need to have leading 0s in the instance that they are less than 3 characters. The code snippet below is almost exactly what I have right now.
CASE
WHEN
(Num % 2 = 0
OR Num = '001'
AND NOT (Num = '124'))
THEN /*Do something*/
WHEN
(Num % 2 = 1
OR Num = '002'
AND NOT (Num = '123'))
THEN /*Do a different thing*/
ELSE /*Do something else*/
END
So far my exceptions in the "even" section work, it's just the odd exceptions that appear to not be working. (i.e. Num = '001' is being treated as even, but Num = '124' is ALSO still being treated as even.) It appears as though it is still reading it as even and then not going to the next WHEN statement. I have also tried using a few other variations with no success.
AND Number <> '124'
AND Number <> 124
AND NOT Number = 124
I can't figure out why these aren't working! Do I need to put the exceptions first? Do the AND exceptions need to go before the OR exceptions? I have about 10 total exceptions to deal with, and all of the exceptions in the "odd" section are not working.
So you should really have a look at the SQL server's operator precedence chart.
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/operator-precedence-transact-sql?view=sql-server-ver15
There AND ranks higher over OR, so AND is evaluated first. For same rank operators they are always left to right.
lets look at even condition now.
WHEN
(Num % 2 = 0
OR Num = '001'
AND NOT (Num = '124'))
THEN /*Do something*/
This really means
(Num % 2 = 0
OR (Num = '001'
AND NOT (Num = '124')))
So if Num is 124 the first part Num%2 is true and lets it be processed.
What you really need here
(Num % 2 = 0
OR Num = '001')
AND NOT (Num = '124')
TLDR: Put parenthesis explicitly to avoid SQL to interpret incorrectly

How to ignore specific string value when using pattern and patindex function in SQL Server Query?

I have this query here.
WITH Cte_Reverse
AS (
SELECT CASE PATINDEX('%[^0-9.- ]%', REVERSE(EmailName))
WHEN 0
THEN REVERSE(EmailName)
ELSE left(REVERSE(EmailName), PATINDEX('%[^0-9.- ]%', REVERSE(EmailName)) - 1)
END AS Platform_Campaign_ID,
EmailName
FROM [Arrakis].[xtemp].[Stage_SendJobs_Marketing]
)
SELECT REVERSE(Platform_Campaign_ID) AS Platform_Campaign_ID, EmailName
FROM Cte_Reverse
WHERE REVERSE(Platform_Campaign_ID) <> '2020'
AND REVERSE(Platform_Campaign_ID) <> ''
AND LEN(REVERSE(Platform_Campaign_ID)) = 4;
It is working for the most part, below is a screenshot of the result set.
The query I posted above extracts the 4 numbers to the right out of the initial value that is set for the column I am extracting out of. But I am unable to figure out how I can also have the query ignore cases when the right most value is -v2, -v1, etc. essentially anything with -v and whatever number version it is.
If you want four digits, then one method is:
select substring(emailname, patindex('%[0-9][0-9][0-9][0-9]%', emailname), 4)

SQL Server: interpreting 'y' as BIT value

In C, when you compared true/false value to 1/0, it worked very well.
I would want the similar possibility with SQL Server - when I have a bit column, I would like to compare myBitField = 'y' / myBitField = 'n'
Is there anything I can do about that? Maybe change some SQL interpreter settings or something?
Example of what I would like to do:
select * from
(
select CAST(1 AS BIT) as result
) as main
where main.result = 'y'
Currently, it throws an error, and I would like it to return 1/true/'y', whatever, but I would like it to be able to make that comparison.
I suppose you want to do it for some yes/no thing. But this is generally a wrong concept, your application which is accessing the SQL Server should interpret y as a 1 and n as a 0 and afterwards set the correct parameters for the query. You should not (actually I'm temped to write "must not") do this in SQL Server, that's what you have a business logic for.
As others have said, BIT and CHAR / VARCHAR are entirely different datatypes. But if you want to cast them during the select, you can use CASE expression like so:
-- Reading string as BIT
SELECT CAST(CASE RESULT WHEN 'Y' THEN 1 WHEN 'N' THEN 0 ELSE NULL END AS BIT) RESULT
-- Reading BIT as string
SELECT CAST(CASE RESULT WHEN 1 THEN 'Y' WHEN 0 THEN 'N' ELSE NULL END AS CHAR(1)) RESULT
And that's about as far as your options go here, far as I can understand. :)

SQL 'CASE WHEN x' vs. 'CASE x WHEN' with greater-than condition?

This is a questions about the two ways to use the SELECT CASE in MS SQL [CASE WHEN X = Y] and [CASE X WHEN Y]
I am trying to define buckets for a field based on its values. I would need to use ranges, so it is necessary to use the "<" or ">" identifiers.
As a simple example, I know it works like this:
SELECT CASE WHEN x < 0 THEN 'a' WHEN X > 100 THEN 'b' ELSE 'c' END
Now I have to write a lot of these, there will be more than 3 buckets and the field names are quite long, so this becomes very difficult to keep clean and easy to follow. I was hoping to use the other way of the select command but to me it looks like I can only use it with equals:
SELECT CASE X WHEN 0 then 'y' ELSE 'z' END
But how can I use this form to specify range conditions just as above? Something like:
SELECT CASE X WHEN < 0 THEN 'a' WHEN > 100 THEN 'b' ELSE "c" END
This one does not work.
Thank You!
As an alternative approach, remember that it is possible to do math on the value that is the input to the "simple" CASE statement. I often use ROUND for this purpose, like this:
SELECT
CASE ROUND(X, -2, 1)
WHEN 0 THEN 'b' -- 0-99
WHEN 100 THEN 'c' -- 100-199
ELSE 'a' -- 200+
END
Since your example includes both positive and negative open-ended ranges, this approach may not work for you.
Still another approach: if you are only thinking about readability in the SELECT statement, you could write a scalar-valued function to hide all the messiness:
CREATE FUNCTION dbo.ufn_SortValuesIntoBuckets (#inputValue INT) RETURNS VARCHAR(10) AS
BEGIN
DECLARE #outputValue VARCHAR(10);
SELECT #outputValue =
CASE WHEN #inputValue < 0 THEN 'a'
WHEN #inputValue BETWEEN 0 AND 100 THEN 'b'
WHEN #inputValue > 100 THEN 'c'
END;
RETURN #outputValue;
END;
GO
So now your SELECT statement is just:
SELECT dbo.ufn_SortValuesIntoBuckets(X);
One final consideration: I have often found, during benchmark testing, that the "searched" form (which you are trying to avoid) actually has better performance than the "simple" form, depending how many CASEs you have. So if performance is a consideration, it might be worth your while to do a little benchmarking before you change things around too much.
There is no such "third form" of the CASE - only the searched and the simple cases are supported *.
You need to use the searched kind (i.e. with separate conditions) even though the variable to which you apply the condition is always the same.
If you are looking to avoid repetition in your SQL when X represents a complex expression, use WITH clause or a nested query to assign a name to the expression that you are selecting.
* The official name of your first example is "searched CASE expression"; your second example is called the "simple CASE expression".
It won't look so bad using BETWEENs:
SELECT CASE
WHEN X < 0 THEN 'a'
WHEN X BETWEEN 0 AND 100 THEN 'b'
WHEN X BETWEEN 100 AND 200 THEN 'c'
ELSE 'd' END
That is actually very interesting question. It resembles C# 9.0 relational pattern
SELECT CASE X WHEN < 0 THEN 'a'
WHEN > 100 THEN 'b'
ELSE 'c'
END
C# 9.0
DeliveryTruck t when t.GrossWeightClass switch
{
> 5000 => 10.00m + 5.00m,
< 3000 => 10.00m - 2.00m,
_ => 10.00m,
},
SQL CASE expression as mentioned in previous answers has two forms: simple and searched.
But SQL standard defines also
SQL:2003 Extended CASE expression(F262). This feature is barely adopted by major vendors.
case — Conditional Expressions by Markus Winand
The so-called extended case accepts a comparison operator right after when and thus lifts the limitation that simple case always uses equals (=) comparisons. The following example uses the less than operator (<) to map values into intervals. It also relies on the precedence of when clauses: the first true condition wins.
CASE x WHEN < 0 THEN '< 0'
WHEN < 10 THEN '[0, 10['
WHEN < 100 THEN '[10, 100['
ELSE '>100'
END

Oracle: How can I get a value 'TRUE' or 'FALSE' comparing two NUMBERS in a query?

I want to compare two numbers. Let's take i.e. 1 and 2.
I've tried to write the following query but it simply doesn't work as expected (Toad says: ORA-00923: FROM keyword not found where expected):
SELECT 1 > 2 from dual
The DECODE is something like a Switch case, so how can I get the result of an expression evalutation (i.e. a number comparison) putting it in the select list?
I have found a solution using a functions instead of an expression in the SELECT LIST: i.e.
select DECODE(SIGN(actual - target)
, -1, 'NO Bonus for you'
, 0,'Just made it'
, 1, 'Congrats, you are a winner')
from some_table
Is there a more elegant way?
Also how do I compare two dates?
There is no boolean types in sql (at least in oracle).
you can use case:
SELECT CASE when 1 > 2 THEN 1 ELSE 0 END FROM dual
But your solution (decode) is also good, read here
The SIGN() function is indeed probably the best way of classifying (in)equality that may be of interest to you if you want to test a > b, a = b and a < b, and it will accept date-date or numeric-numeric as an argument.
I'd use a Case statement by preference, rather than a decode.
Select
case sign(actual-target)
when -1 then ...
when 0 then ...
when 1 then ...
end
SELECT (CASE
WHEN (SIGN(actual - target) > 0 ) THEN
'NO Bonus for you'
ELSE
'Just made it' END)
FROM dual
you can compare two dates with sql
METHOD (1):
SELECT TO_DATE('01/01/2012') - TO_DATE('01/01/2012')
FROM DUAL--gives zero
METHOD (2):
SELECT CASE
when MONTHS_BETWEEN('01/01/2012','01/01/2010') > 0
THEN 'FIRST IS GREATER'
ELSE 'SECOND IS GREATER OR EQUAL' END
FROM dual
sorry i cant format the code the formatting toolbar disappeared !
do any one know why?