How does Varchar equality work in SQL expressions? - sql

How does varchar equality work in SQL and why? '1' is different from '1 ' actually. See the spaces in the right hand side operand:
SELECT CASE
WHEN '1' = '1 ' THEN 'yes'
ELSE 'no'
END
-- results in yes
The output is 'yes', but why?

This behavior is in accordance with the specs. From a very old version of specs:
3) The comparison of two character strings is determined as follows:
a) If the length in characters of X is not equal to the length in
characters of Y, then the shorter string is effectively replaced, for
the purposes of comparison, with a copy of itself that has been
extended to the length of the longer string by concatenation on the
right of one or more pad characters, where the pad character is chosen
based on CS. [...] Otherwise, the pad character is a <space>.
In plain english, yes, 1 and 1 ​ are compared equal but not 1 and ​ 1.

SQL will ignore all the trailing spaces while comparing your varchar value on =,>,<,>=,<= operators.
if you compare ' 1' and '1' then it give false. But '1 ' and '1' give true.
; with cte as (
SELECT ' 1' as a, '1' as b )
select case when a= b then 'dd' else 'ff' end from cte
Result
--------
ff
; with cte as (
SELECT '1 ' as a, '1' as b )
select case when a= b then 'dd' else 'ff' end from cte
Result
------
dd
It is kind sql internally perform RTRIM by default.
You may find this link for more info LINK

You are comparing two strings. When a string has spaces, it is different.
You can remove all spaces with REPLACE('1 ', ' ', '').

the two string '1' and '1 ' are not equal cause the space ..
for avoid this you should use trim
SELECT CASE
WHEN trim( '1' ) = trim('1 ' ) THEN 'yes'
ELSE 'no'
END

Related

Trim leading zeroes if it is numeric and not trim zeroes if it is alphanumeric

In a column, there are numeric and alphanumeric values starting with '0'.
How to trim leading zeroes if it is numeric and should not trim zeroes if it is alphanumeric in Oracle.
I need to use it in WHERE Condition.
Ex.
000012345 should be 12345.
012321 should be 12321.
00012JY12 should be 00012JY12.
This is what I tried:
SELECT COUNT(*)
FROM <TABLE 1> ONN, <TABLE 2> SV
WHERE SV.CSA_SHP_VISIT_STG_SEQ_ID=ONN.CSA_SHOP_VIST_SEQ_ID
AND EXISTS (SELECT '1' FROM <TABLE 3> TMP
WHERE TRIM(SV.WORK_ORDER_NUM) = TRIM(TMP.WORK_ORDER_NUM)
AND PLANT IN ('EMA')
AND regexp_replace(TRIM(ONN.INSTLD_PART), '^0+([[:digit:]]+)$',
'\1')=TRIM(TMP.INSTLD_PART) AND
TRIM(ONN.INSTLD_PART_SERIAL_NUM)=TRIM(TMP.INSTLD_PART_SERIAL_NUM) AND
nvl(to_number(TRIM(ONN.INSTLD_PART_CSN)),0)=
nvl(to_number(TRIM(TMP.INSTLD_PART_CSN)),0)
and REGEXP_LIKE(tmp.INSTLD_PART_CSN, '^-?\d+(\.\d+)?$'))
Whenever possible (in this case it is), use standard string functions, such as SUBSTR, INSTR, TRANSLATE, etc. instead of regular expression functions. Regular expressions are much more powerful, but also much more time consuming (precisely for that reason), so they should be used only when really needed.
If the column name is str, then:
case when translate(str, 'z0123456789', 'z') is null
then ltrim(str, '0')
else str end
TRANSLATE will translate z to itself, all the digits to NULL, and all other characters to themselves. (Alas, the z, or SOME non-digit character, is needed.)
The input is all-digits if and only if the result of TRANSLATE is NULL.
Demo:
select str, case when translate(str, 'z0123456789', 'z') is null
then ltrim(str, '0')
else str
end as new_str
from
(
select '000012345' as str from dual union all
select '012321' as str from dual union all
select '00012JY12' as str from dual
);
STR NEW_STR
--------- ---------
000012345 12345
012321 12321
00012JY12 00012JY12
Use regexp_replace(col, '^0+([[:digit:]]+)$', '\1').
This replaces strings that only consist of leading zeros and trailing digits with the trailing digits alone, thus removing the zeros.
Sample query:
select col, regexp_replace(col, '^0+([[:digit:]]+)$', '\1') as newvalue
from
(
select '000012345' as col from dual
union all
select '012321' as col from dual
union all
select '00012JY12' as col from dual
);
Result:
COL | NEWVALUE
----------+----------
000012345 | 12345
012321 | 12321
00012JY12 | 00012JY12
If you are using Oracle 12.2, you could use the error handling of the CAST expression.
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/CAST.html#GUID-5A70235E-1209-4281-8521-B94497AAEF75
Along that:
CASE WHEN CAST(<expression> AS NUMERIC DEFAULT NULL ON CONVERSION ERROR) IS NULL
THEN <expression>
ELSE TRIM(LEADING '0' FROM <expression>)
END
Replace <expression> with your column name (or whatever). I'm using null as magic value in the default null on conversion error clause but this does no harm as null input will then just match the THEN clause and pass the null through.
You can create a function that check if it is numeric or not, see this link for the function sample,
check if "it's a number" function in Oracle
You can TRIM the zeros of numeric value just by adding 0 to it,
Sample code:
--get the IS_NUMERIC function from the link
SELECT DECODE(IS_NUMERIC(col1), 'Y', col1+0, 'N', col1)
FROM your_table;

PL SQL replace conditionally suggestion

I need to replace the entire word with 0 if the word has any non-digit character. For example, if digital_word='22B4' then replace with 0, else if digital_word='224' then do not replace.
SELECT replace_funtion(digital_word,'has non numeric character pattern',0,digital_word)
FROM dual;
I tried decode, regexp_instr, regexp_replace but could not come up with the right solution.
Please advise.
Thank you.
the idea is simple - you need check if the value is numeric or not
script:
with nums as
(
select '123' as num from dual union all
select '456' as num from dual union all
select '7A9' as num from dual union all
select '098' as num from dual
)
select n.*
,nvl2(LENGTH(TRIM(TRANSLATE(num, ' +-.0123456789', ' '))),'0',num)
from nums n
result
1 123 123
2 456 456
3 7A9 0
4 098 098
see more articles below to see which way is better to you
How can I determine if a string is numeric in SQL?
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:15321803936685
How to tell if a value is not numeric in Oracle?
You might try the following:
SELECT CASE WHEN REGEXP_LIKE(digital_word, '\D') THEN '0' ELSE digital_word END
FROM dual;
The regular expression class \D matches any non-digit character. You could also use [^0-9] to the same effect:
SELECT CASE WHEN REGEXP_LIKE(digital_word, '\D') THEN '0' ELSE digital_word END
FROM dual;
Alternately you could see if the value of digital_word is made up of nothing but digits:
SELECT CASE WHEN REGEXP_LIKE(digital_word, '^\d+$') THEN digital_word ELSE '0' END
FROM dual;
Hope this helps.
The fastest way is to replace all digits with null (to simply delete them) and see if anything is left. You don't need regular expressions (slow!) for this, you just need the standard string function TRANSLATE().
Unfortunately, Oracle has to work around their own inconsistent treatment of NULL - sometimes as empty string, sometimes not. In the case of the TRANSLATE() function, you can't simply translate every digit to nothing; you must also translate a non-digit character to itself, so that the third argument is not an empty string (which is treated as a real NULL, as in relational theory). See the Oracle documentation for the TRANSLATE() function. https://docs.oracle.com/cd/E11882_01/server.112/e41084/functions216.htm#SQLRF06145
Then, the result can be obtained with a CASE expression (or various forms of NULL handling functions; I prefer CASE, which is SQL Standard):
with
nums ( num ) as (
select '123' from dual union all
select '-56' from dual union all
select '7A9' from dual union all
select '0.9' from dual
)
-- End of simulated inputs (for testing only, not part of the solution).
-- SQL query begins BELOW THIS LINE. Use your own table and column names.
select num,
case when translate(num, 'z0123456789', 'z') is null
then num
else '0'
end as result
from nums
;
NUM RESULT
--- ------
123 123
-56 0
7A9 0
0.9 0
Note: everything here is in varchar2 data type (or some other kind of string data type). If the results should be converted to number, wrap the entire case expression within TO_NUMBER(). Note also that the strings '-56' and '0.9' are not all-digits (they contain non-digits), so the result is '0' for both. If this is not what you needed, you must correct the problem statement in the original post.
Something like the following update query will help you:
update [table] set [col] = '0'
where REGEXP_LIKE([col], '.*\D.*', 'i')

How to remove the begining and ending characters if those are '0' in SQL Server

I currently have a table named DATA it has entries like the following:
abc000
ab000cde
000abc
I just want to remove all 0 from beginning and the end. If 0 comes in between the character then it will remain same.
This also works for leading and trailing zeros at the same time:
declare #s varchar(15) = '00abc00efg000'
select substring(#s,
patindex('%[^0]%', #s),
len(#s)-patindex('%[^0]%', reverse(#s))-patindex('%[^0]%', #s)+2);
Description: this is substring from first nonzero symbol till first nonzero symbol in reversed string.
Say your data exists in column called Col1, then this expression should do it
select CASE
WHEN RIGHT(col1 , 1) = '0'
THEN SUBSTRING(col1,0,PATINDEX('%[A-Z1-9]%',REVERSE(col1)))
WHEN LEFT(col1 , 1) = '0'
THEN SUBSTRING(col1,PATINDEX('%[A-Z1-9]%',col1),LEN(col1))
ELSE
Col1
END AS 'ParsedCol1'
FROM Data
I use this trick:
SELECT
REPLACE(REPLACE(RTRIM(LTRIM(REPLACE(REPLACE(col1, ' ', CHAR(8)), '0', ' '))), ' ', '0'), CHAR(8), ' ')
FROM
yourTable
This may works for SQL, as this removes leading & trailing "000" from your string.
SELECT TRIM(BOTH ‘000’ FROM
‘your_data_table_column’);
See more
http://www.mydigitallife.info/remove-or-trim-first-or-last-few-characters-in-mysql-database-with-sql/
http://www.w3resource.com/mysql/string-functions/mysql-trim-function.php

oracle searching word within the input string

i have to find out INPUT string word found within the other string that is pipe delimited,i am trying below way but it is surprisingly return 'Y' instead of 'N'.please let me know what i am doing in wrong in below cast statement.
CASE
WHEN REGEXP_INSTR('TCS|XY|XZ','CS',1,1,1,'i') > 0
THEN 'Y'
ELSE 'N'
END
Regards,
Raj
There is really no need to use regexp_instr() regular expression function. If you just need to know if a particular character literal is part of another character literal, instr() function will completely cover your needs:
with t1(col) as(
select 'TCS|XY|XZ' from dual union all
select 'TAB|XY|XZ' from dual
)
select col
, case
when instr(col, 'CS') > 0
then 'Y'
else 'N'
end as Is_Part
from t1
Result:
COL IS_PART
--------- -------
TCS|XY|XZ Y
TAB|XY|XZ N
Edit
If you need to take vertical bars into consideration - returning yes only if there is a standalone CS sub-string surrounded by vertical bars |CS| then yes, you could use regexp_instr() regular expression function as follows:
with t1(col) as(
select 'TCS|XY|XZ|' from dual
)
select col
, case
when regexp_instr(col, '(\||^)CS(\||$)', 1, 1, 0, 'i') > 0
then 'YES'
else 'NO'
end as res
from t1
Result:
COL RES
---------- ---
TCS|XY|XZ| NO
Note: If a character literal is dynamic you could use a concatenation operator || to form a search pattern '(\||^)' || <<'character literal', column or variable>> || '(\||$)'
The first field (TCS) contains CS which counts as a match.
If you want to match an entire field you can do like this:
CASE
WHEN REGEXP_INSTR('|' || 'TCS|XY|XZ' || '|' , '\|' || 'CS' || '\|',1,1,1,'i') > 0
THEN 'Y'
ELSE 'N'
END
Add the delimiter to your query string to "anchor" the search to whole fields. To be able to match the first and last field I also added the delimiter to the searched string.

DB2- How to check if varchar field value has integers

Is there an inbuilt DB2 function or any query to check if the character i have is a number?
(I cannot use user defined functions)
Doc Link
CASE
WHEN LENGTH(RTRIM(TRANSLATE(test_str, '*', ' 0123456789'))) = 0
THEN 'All digits'
ELSE 'No'
END
if you version of db2 can use regexp_like you can do it:
number with "." as decimal symbol:
select * from yourtable
where REGEXP_LIKE(trim(yourzone) , '^\d+(\.\d*)?$')
number with "," as decimal symbol:
select * from yourtable
where REGEXP_LIKE(trim(yourzone) , '^\d+(\,\d*)?$')
number without decimal symbol ( integer only, your ask)
select * from yourtable
where REGEXP_LIKE(trim(yourzone) , '^\d+$')
There are many approaches. Take a look at that solution using only two functions:
CASE
WHEN REPLACE(TRANSLATE(test_str, '0','123456789','0'),'0','') = ''
THEN 'All digits'
ELSE 'Not all digits'
END
In general - less functions - better performance :)
Use ASCII function to get character value and compare that it is between 48 '0' and 57 '9'
ASCII Table
ASCII Function
Returns the ASCII code value of the leftmost character of the argument as an integer.
The answer by xQbert is not completely correct.
What you actually need is a * for every character in the fromString (and the space needs to be removed) and the length of the to string needs to be the same as the length of the original string.
so it will look like this:
CASE
WHEN LENGTH(RTRIM(TRANSLATE(test_str, '**********', '0123456789'))) = LENGTH(RTRIM(test_str))
THEN 'All digits'
ELSE 'No'
END
Returns numeric where char field is all numerics with no leading or trailing spaces. ie; All characters in the field are numeric:
where translate(char_field, 'X ',' 0123456789') = ' '
Returns non-numeric values with leading spaces considered non-numeric, but trailing spaces ignored. ie; non-numeric if there are leading spaces, but not if there are trailing spaces. This is a common occurrence for mainframe/Cobol-loaded fields:
where not ( length(rtrim(translate(substr(char_field,1,length(rtrim(char_field))),' ','0123456789'))) = 0)
Returns numeric with trailing, but not leading spaces after value. ie; Leading spaces are treated as non-numeric, but trailing spaces are ignored. Again, common for mainframe/Cobol CHAR fields:
where ( length(rtrim(translate(substr(char_field,1,length(rtrim(char_field))),'X ',' 0123456789'))) = 0)
Returns numeric with leading & trailing spaces. ie; ignores leading and trailing spaces in determining field is "numeric":
where ( length(ltrim(rtrim(translate(substr(char_field,1,length(ltrim(rtrim(char_field)))),' ','0123456789')))) = 0)
I have made more error-prone version based on the idea xQbert exposed, added intermedia result, some examples and to_integer column which converts string value safely to integer:
select
test_str
, TRIM(TRANSLATE(replace(trim(test_str), ' ', 'x'), ' ', '0123456789'))
, case when length(TRIM(TRANSLATE(replace(trim(test_str), ' ', 'x'), ' ', '0123456789')))=0
then cast(test_str as int) else null end to_integer
, case when length(TRIM(TRANSLATE(replace(trim(test_str), ' ', 'x'), ' ', '0123456789')))=0
then 'integer' else 'not integer' end is_integer
from (VALUES
(' 123 ' )
,(' abc ' )
,(' a12 ' )
,(' 12 3 ')
,(' 99.3 ')
,('993' )
) AS X(test_str)
;
The result for this example set is:
TEST_STR 2 TO_INTEGER IS_INTEGER
-------- -------- ----------- -----------
123 123 integer
abc abc - not integer
a12 a - not integer
12 3 x - not integer
99.3 . - not integer
993 993 integer