I'm struggling to combine two expression into one so that I can remove trailing 'mm' chars of a varchar column which holds values like 3.214mm and use those chars as numeric values.
The problem I have is that there can be also null or empty string values and I can't find a way to combine both expressions below.
Example: SQLfiddle
DECLARE #string varchar(128)
SET #string = '4.123mm'
SELECT ISNULL(NULLIF(#string,''),NULL) As MyString ;
DECLARE #createNumber varchar(128)
SET #createNumber = '4.123mm'
select LEFT(#createNumber, NULLIF (LEN(#createNumber) - 2, - 1))As MyNumber
DECLARE #createNumber varchar(128)
SET #createNumber = ''
select reverse(stuff(reverse(#createNumber), 1,2, ''))
This will return null if createnumber is shorter than 2 characters.
One way to handle mm/''/null;
select cast(isnull(replace('0' + #createNumber, 'mm', ''), 0) as decimal(6,3))
Related
I have table with some strings. I would like make select with condition string = eqauls something
I Dont have any other strings....
The select returns more rows when I Have:
What is wrong?
DECLARE #C VARCHAR(2) = 'A'+SPACE(1)
DECLARE #T TABLE (id INT NOT NULL, string VARCHAR(200) NOT NULL)
INSERT INTO #T
(
id,
string
)
VALUES
( 1, 'A'), (2,'A'+SPACE(1))
SELECT * FROM #T WHERE string = #C--With space only
Returns:
id string
1 A
2 A
I know hot to make select LIKE '%.... '.
I want to know why TSQL returns more rows.
SQL 2019, MSSQL version 18.9.2
SQL Server follows the ANSI standard when it comes to comparing strings with =. Read a longer description over here: https://dba.stackexchange.com/a/10511/7656
The bottom line is, you can't check for trailing spaces with =. Use LIKE without any % instead.
Given
CREATE TABLE T (id INT NOT NULL, string VARCHAR(200) NOT NULL)
INSERT INTO T VALUES (1, 'A')
INSERT INTO T VALUES (2, 'A ')
this
SELECT id, len(string) len, datalength(string) datalength FROM T
results in
id
len
datalength
1
1
1
2
1
2
and
SELECT id FROM T WHERE string LIKE 'A '
will give you 2. See http://sqlfiddle.com/#!18/2356c9/1
You can use one of the following solutions
-- Option 1: add to the filter the condition `DATALENGTH(#C) = DATALENGTH(string)` or 'DATALENGTH(#C) < DATALENGTH(string)'
SELECT * FROM #T WHERE string = #C and DATALENGTH(#C) <= DATALENGTH(string)
-- Option 2: Use `LIKE` and add the expresion '%'
SELECT * FROM #T WHERE string like #C + '%'
The = operator ignores trailing spaces just like LEN(). The LIKE operator does not
SELECT * FROM #T WHERE string LIKE #C
You can prove this with
SELECT CASE WHEN 'A' = 'A ' THEN 'True' ELSE 'False' END -- True
SELECT CASE WHEN 'A' = ' A' THEN 'True' ELSE 'False' END -- False because of leading space
SELECT CASE WHEN 'A' LIKE 'A ' THEN 'True' ELSE 'False' END -- False
SELECT LEN(string), FROM #T -- both return 1
I currently have to a code in ABAP which contains a String that has multiple words that start with Capital letters/Uppercase and there is no space in-between.
I have to separate it into an internal table like this:
INPUT :
NameAgeAddress
OUTPUT :
Name
Age
Address
Here is the shortest code I could find, which uses a regular expression combined with SPLIT:
SPLIT replace( val = 'NameAgeAddress' regex = `(?!^.)\u` with = ` $0` occ = 0 )
AT ` `
INTO TABLE itab.
So, replace converts 'NameAgeAddress' into 'Name Age Address' and SPLIT puts the 3 words into an internal table.
Details:
(?!^.) to say the next character to find (\u) should not be the first character
\u being any upper case letter
$0 to replace the found string ($0) by itself preceded with a space character
occ = 0 to replace all occurrences
Unfortunately, the SPLIT statement in ABAP does not allow a regex as separator expression. Therefore, we have to use progressive matching, which is a bit awkward in ABAP:
report zz_test_split_capital.
parameters: p_input type string default 'NameAgeAddress' lower case.
data: output type stringtab,
off type i,
moff type i,
mlen type i.
while off < strlen( p_input ).
find regex '[A-Z][^A-Z]*'
in section offset off of p_input
match offset moff match length mlen.
if sy-subrc eq 0.
append substring( val = p_input off = moff len = mlen ) to output.
off = moff + mlen.
else.
exit.
endif.
endwhile.
cl_demo_output=>display_data( output ).
Just for comparison, the following statement would do the job in Perl:
my $input = "NameAgeAddress";
my #output = split /(?=[A-Z])/, $input;
# gives #output = ('Name','Age','Address')
It is easy with using regular expressions. The solution could look like this.
REPORT ZZZ.
DATA: g_string TYPE string VALUE `NameAgeAddress`.
DATA(gcl_regex) = NEW cl_abap_regex( pattern = `[A-Z]{1}[a-z]+` ).
DATA(gcl_matcher) = gcl_regex->create_matcher( text = g_string ).
WHILE gcl_matcher->find_next( ).
DATA(g_match_result) = gcl_matcher->get_match( ).
WRITE / g_string+g_match_result-offset(g_match_result-length).
ENDWHILE.
For when regular expressions are just overkill and plain old ABAP will do:
DATA(str) = 'NameAgeAddress'.
IF str CA sy-abcde.
DATA(off) = 0.
DO.
data(tailstart) = off + 1.
IF str+tailstart CA sy-abcde.
DATA(len) = sy-fdpos + 1.
WRITE: / str+off(len).
add len to off.
ELSE.
EXIT.
ENDIF.
ENDDO.
write / str+off.
ENDIF.
If you do not want to use or cannot use Regex, here another solution:
DATA: lf_input TYPE string VALUE 'NameAgeAddress',
lf_offset TYPE i,
lf_current_letter TYPE char1,
lf_letter_in_capital TYPE char1,
lf_word TYPE string,
lt_word LIKE TABLE OF lf_word.
DO strlen( lf_input ) TIMES.
lf_offset = sy-index - 1.
lf_current_letter = lf_input+lf_offset(1).
lf_letter_in_capital = to_upper( lf_current_letter ).
IF lf_current_letter = lf_letter_in_capital.
APPEND INITIAL LINE TO lt_word ASSIGNING FIELD-SYMBOL(<ls_word>).
ENDIF.
IF <ls_word> IS ASSIGNED. "if input string does not start with capital letter
<ls_word> = <ls_word> && lf_current_letter.
ENDIF.
ENDDO.
I need to mask a string field for example phone number "0144567890" into "014XXXX890". Only first three and last three character need to remained, others turn it into "X".Also I wish to make it dynamically which can mask any lengths of string.Thanks.
If you know that the maximum length of the string is say 10,
use this 'XXXXXXXXXX' as a pattern from which to extract the Xs like this:
select
substr(col, 1, 3) ||
substr('XXXXXXXXXX', 1, length(col) - 6) ||
substr(col, length(col) - 2)
from tablename
col is the name of the column.
I have the following string 2014/15 passed as a parameter to my procedure and I need to increment the 4 and 5 by 1 so I end up with 2015/16.
Obviously the string is a VARCHAR so I can't use any normal arithmetic functions, nor DATEADD. The parameter must be passed in as is and I must derive a year above and a year below as well as using the parameter.
To simplify, if you feed in 2014/15 then in my SP I will need to use 2013/14, 2014/15 and 2015/16 in various parts or the SP all derived from that 1 string.
Something you can do is this:
DECLARE #date VARCHAR(MAX)
SET #date = '2014/15'
SELECT
CAST(
CAST(
SUBSTRING(#date, 0, CHARINDEX('/', #date))
AS INTEGER) + 1
AS VARCHAR(4))
+ '/'
+ RIGHT(
CAST(
CAST(
SUBSTRING(#date, 0, CHARINDEX('/', #date))
AS INTEGER) + 2
AS VARCHAR(4))
, 2)
Here is a SQLFiddle with how the code works.
The first part of the query will return the year 2014 incremented by 1.
It will then append a slash to it. Using the first date again (2014), which is extracted in the same manner, I increment it by 2. I then convert this value to a VARCHAR value so I can do string operations on it (RIGHT() function).
I then use the RIGHT() function to extract the last 2 characters, which I append to my original string.
Here, this might help you:
DECLARE #Input varchar(10)
SET #Input = '2014/15'
DECLARE #First INT, #Second INT
SET #First = SUBSTRING(#Input, 1, CHARINDEX('/', #Input) - 1)
SET #Second = SUBSTRING(#Input, CHARINDEX('/', #Input) + 1, LEN(#Input))
SELECT CONVERT(VARCHAR(10), (#First + 1)) + '/' + CONVERT(VARCHAR(10), (#Second + 1))
Basically it pulls the two components which are separated by the forward slash character / into INT variables which you can increment or decrement as needed, and then it converts those result values back to VARCHAR and puts that back together with the separator character.
The following uses the documented implicit type conversions (Ref.) to convert the substrings to integers. Note that it does not use CharIndex to locate the solidus ("/"), but assumes that the column has exactly the format you specified: four digits, solidus, two digits.
declare #Sample as Char(7) = '2014/15';
select Cast( Left( #Sample, 4 ) + 1 as Char(4) ) + '/' +
Cast( Right( #Sample, 2 ) + 1 as Char(2) );
I came up with the following but it isn't particularly elegant
SUBSTRING(#Date, 1, 3)+CAST(CAST(SUBSTRING(#Date, 4,1)AS INT)+1 AS VARCHAR)+'/'+SUBSTRING(#Date, 6, 1)+CAST(CAST(SUBSTRING(#Date, 7,1)AS INT)+1 AS VARCHAR)
How can I read each character in a String? For example, I want to read each character in String "a7m4d0". After that I want to verify that each character is a character or a number. Any tips or ideas?
DATA: smth TYPE string VALUE `qwert1yua22sd123bnm,`,
index TYPE i,
length TYPE i,
char TYPE c,
num TYPE i.
length = STRLEN( smth ).
WHILE index < length.
char = smth+index(1).
TRY .
num = char.
WRITE: / num,'was a number'.
CATCH cx_sy_conversion_no_number.
WRITE: / char,'was no number'.
ENDTRY.
ADD 1 TO index.
ENDWHILE.
Here's your problem solved :P
A bit convoluted and on a recent 740 ABAP server. :)
DATA: lv_text TYPE string VALUE `a7m4d0`.
DO strlen( lv_text ) TIMES.
DATA(lv_single) = substring( val = lv_text off = sy-index - 1 len = 1 ) && ` is ` &&
COND string( WHEN substring( val = lv_text off = sy-index - 1 len = 1 ) CO '0123456789' THEN 'Numeric'
ELSE 'Character' ).
WRITE : / lv_single.
ENDDO.
Here is how you can access a single character within a string:
This example will extract out the character "t" into the variable "lv_char1".
DATA: lv_string TYPE char10,
lv_char TYPE char1.
lv_string = "Something";
lv_char1 = lv_string+4(1).
Appending "+4" to the string name specifies the offset from the start of the string (in this case 4), and "(1)" specifies the number of characters to pick up.
See the documentation here for more info:
http://help.sap.com/saphelp_nw04/Helpdata/EN/fc/eb341a358411d1829f0000e829fbfe/content.htm
If you want to look at each character in turn, you could get the length of the field using "strlen( )" and do a loop for each character.
One more approach
PERFORM analyze_string USING `qwert1yua22sd123bnm,`.
FORM analyze_string USING VALUE(p_string) TYPE string.
WHILE p_string IS NOT INITIAL.
IF p_string(1) CA '0123456798'.
WRITE: / p_string(1) , 'was a number'.
ELSE.
WRITE: / p_string(1) , 'was no number'.
ENDIF.
p_string = p_string+1.
ENDWHILE.
ENDFORM.
No DATA statements, string functions or explicit indexing required.
I know the post it's old but this might be useful, this is what use :)
DATA lv_counter TYPE i.
DO STRLEN( lv_word ) TIMES.
IF lv_word+lv_counter(1) CA '0123456789'
"It's a number
ENDIF.
lv_counter = lv_counter + 1.
ENDDO.