Strange phenomenon with substring and charindex - sql

When comparing the code snippets below, you can see that the last element of the 'result 1' result set, only has one character (a comma) appending the number, whereas the other numbers (rows 1 - 3) have a comma and a number appending the 4 digits that I want.
In the 'Result 2' result set, I specifically change the length of the substring to be the string length minus two characters, yet the last element only removes a single element, the trailing comma, while the rows 1 - 3 remove both the number and the trailing comma. There is no blank space in the last row. Please could someone advise why this is happening?
Code 1:
select substring(c,2,charindex(',',c,2)) as empno
from table t
where len(c) > 1
and substring(c,1,1) = ','
Result 1:
7654,7
7698,7
7782,7
7788,
Code 2:
select substring(c,2,charindex(',',c,2)-2) as empno
from table t
where len(c) > 1
and substring(c,1,1) = ','
Result 2:
7654
7698
7782
7788
*edit: table t is:-
c
----------------------
,7654,7698,7782,7788,
7654,7698,7782,7788,
654,7698,7782,7788,
54,7698,7782,7788,
4,7698,7782,7788,
,7698,7782,7788,
7698,7782,7788,
698,7782,7788,
98,7782,7788,
8,7782,7788,
,7782,7788,
7782,7788,
782,7788,
82,7788,
2,7788,
,7788,
7788,
788,
88,
8,
,

CHARINDEX:
Returns part of a character, binary, text, or image expression in SQL Server.
is defined as:
CHARINDEX ( expressionToFind , expressionToSearch [ , start_location ] )
AND
SUBSTRING:
Returns part of a character, binary, text, or image expression in SQL Server.
is defined as:
SUBSTRING ( expression ,start , length )
Query1:
substring(c,2,charindex(',',c,2))
In above charIndex returns first position of ',' i.e. 6 in every case.
So the returned value is acting as length for the substring which is 6 and that's why you are getting each record of 6 lengths.
Query 2:
substring(c,2,charindex(',',c,2)-2)
In above charIndex returns first position of ',' i.e. 6 in every case. But also you are reducing the length by subtracting 2 from it.
So the returned value is acting as length for the substring which is 4 now and that's why you are getting each record of 4 lengths in this query.
See this query1 and query2 represent CHARINDEX returned values:
c query1 query2
,7654,7698,7782,7788, 6 4
,7698,7782,7788, 6 4
,7782,7788, 6 4
,7788, 6 4

Related

How does select SUBSTRING('uppercase ', LEN('uppercase')-2, 3) result in "ase"

Please see below query:
select SUBSTRING('uppercase ', LEN('uppercase')-2, 3)
Can someone explain how it is working and giving output as ase
Please help.
SUBSTRING function extracts characters from a string. In additon,LEN function provide the length of string. the LEN('uppercase') would be 9.
SUBSTRING(string, start, length)
your query is like
select SUBSTRING('uppercase ', LEN('uppercase')-2, 3)---equivalent
select SUBSTRING('uppercase ', 9-2, 3) --equivalent
select SUBSTRING('uppercase ', 7, 3)
hence it provide ase
Should be:
select SUBSTRING('uppercase ', LENGTH('uppercase')-2, 3) // Mysql hasn't len function
LENGTH('uppercase') // return 9, the length of string.
SUBSTRING('uppercase ', 9-2, 3) // return a substring from the index of 7 and three characters, that is ase
Go through the documentation of substring function
SUBSTRING ( expression ,start , length )
expression
Is a character, binary, text, ntext, or image expression.
start
Is an integer or bigint expression that specifies where the
returned characters start. (The numbering is 1 based, meaning that the
first character in the expression is 1). If start is less than 1, the
returned expression will begin at the first character that is
specified in expression. In this case, the number of characters that
are returned is the largest value of either the sum of start + length-
1 or 0. If start is greater than the number of characters in the value
expression, a zero-length expression is returned.
length
Is a positive integer or bigint expression that specifies how
many characters of the expression will be returned. If length is
negative, an error is generated and the statement is terminated. If
the sum of start and length is greater than the number of characters
in expression, the whole value expression beginning at start is
returned.
In your case,
SUBSTRING('uppercase ', LEN('uppercase')-2, 3)
SUBSTRING('uppercase ', 9-2, 3)
SUBSTRING('uppercase ', 7, 3)
u p p e r c a s e
1 2 3 4 5 6 7 8 9
<====> (From 7 pick 3 characters)
a s e

Trim leading 0 for length greater than x in a dataset

Take this table for example
Table 1:
Name. ID
David 00513
George 0523
Carmen 3216
In this table, I want to trim the leading 0 for David only, because his ID is greater than 4 digits. I don't want to trim the leading 0 for George
Whats the best way to do this in SQL?
The simplest way is simply:
select right(id, 4)
If you are concerned about ids longer than 4 character but with non-zero initial characters:
select (case when length(id) > 4
then replace(ltrim(replace(id, '0', ' ')), ' ', '0')
else id
end)
If you're not concerned with initial non-zeros getting chopped, then
select substr(ID,-4);
should work. If there is possibility of having more than 4 digits with a non-zero initial, then use
select printf('%04d', ID);
(Assuming that all characters in ID are digits)

sql query about string function

ID MOBILE
1 9869600733
2 9869600793
3 9869600799
all id whose mobile number containing 9 three times(using string functions like replace, substr, etc)... ? (without like , % , etc)
You can use LEN and Replace
Where len(MOBILE)-len(replace(MOBILE ,'9',''))>=3
Note : Some DBMS uses LENGTH instead of LEN
Where length(MOBILE)-length(replace(MOBILE ,'9',''))>=3
DEMO
replace(MOBILE ,'9','') will replace all the 9's with empty
string
length(MOBILE) will count the number of characters in Mobile
column
length(replace(MOBILE ,'9','')) will count the number of characters
in Mobile column as replacing 9's with empty string
length(MOBILE)-length(replace(MOBILE ,'9','')) here the
difference will tell the number of missing characters that is our 9, you can use this difference to count the 9
exactly three '9's:
Select * from mytable
Where len(mobile) - len(replace(mobile, '9', '')) = 3
at least three '9's:
Select * from mytable
Where len(mobile) - len(replace(mobile, '9', '')) >= 3

how to add zeros after decimal in Oracle

I want to add zeroes after the number .
for eg a= 6895
then a= 6895.00
datatype of a is number(12);
I am using the below code .
select to_char(6895,'0000.00') from dual .
I m getting the desired result from above code but
'6895' can be any number.so due to that i need to add '0' in above code manually.
for eg.
select to_char(68955698,'00000000.00') from dual .
Can any one suggest me the better method .
The number format models are the place to start when converting numbers to characters. 0 prepends 0s, which means you'd have to get rid of them somehow. However, 9 means:
Returns value with the specified number of digits with a leading space if positive or with a leading minus if negative. Leading zeros are blank, except for a zero value, which returns a zero for the integer part of the fixed-point number.
So, the following gets you almost there, save for the leading space:
SQL> select to_char(987, '9999.00') from dual;
TO_CHAR(
--------
987.00
You then need to use a format model modifier, FM, which is described thusly:
FM Fill mode. Oracle uses trailing blank characters and leading zeroes
to fill format elements to a constant width. The width is equal to the
display width of the largest element for the relevant format model
...
The FM modifier suppresses the above padding in the return value of
the TO_CHAR function.
This gives you a format model of fm9999.00, which'll work:
SQL> select to_char(987, 'fm9999.00') from dual;
TO_CHAR(
--------
987.00
If you want a lot of digits before the decimal then simply add a lot of 9s.
datatype of a is number(12);
Then use 12 9s in the format model. And, keep the decimal to just 2. So, since the column datatype is NUMBER(12), you cannot have any number more than the given size.
SQL> WITH DATA AS(
2 SELECT 12 num FROM dual union ALL
3 SELECT 234 num FROM dual UNION ALL
4 SELECT 9999 num FROM dual UNION ALL
5 SELECT 123456789 num FROM dual)
6 SELECT to_char(num,'999999999999D99') FROM DATA
7 /
TO_CHAR(NUM,'999
----------------
12.00
234.00
9999.00
123456789.00
SQL>
Update Regarding leading spaces
SQL> select ltrim(to_char(549,'999999999999.00')) from dual;
LTRIM(TO_CHAR(54
----------------
549.00
SQL>
With using CASE and SUBSTR it is very simple.
CASE WHEN SUBSTR(COLUMN_NAME,1,1) = '.' THEN '0'||COLUMN_NAME ELSE COLUMN_NAME END

Formatting hierachical queries with lpad function

SELECT LPAD(last_name, LENGTH(last_name)+(LEVEL*2)-2,'_')
AS org_chart
FROM employees
START WITH last_name='King'
CONNECT BY PRIOR employee_id=manager_id ;
LPAD(char1,n [,char2]) returns char1, left-padded to length n with the sequence
of characters in char2.
This tells SQL to take the LAST_NAME and left-pad it with the '_' character till
the length of the resultant string is equal to the value determined by
LENGTH(last_name)+(LEVEL*2)-2.
For LEVEL = 1. Hence, (2 * 1) - 2 = 2 - 2 = 0.
For LEVEL = 2. Hence, (2 * 2) - 2 = 4 - 2 = 2 . So its gets padded with 2 '_'
characters and is displayed indented.
and also how to determine the formula that length(ename) to be added with level*2-2
the output is king doesn't get padded with '-'
This is the correct output
ORG_CHART
KING
__PAUL
__JONES
____SCOTT
______ADAMS
____FORD
______SMITH
__BLAKE
____ALLEN
____WARD
____MARTIN
____TURNER
____JAMES
__CLARK
____MILLER
but formula lpad(king,4+(l*10)-10,'-')=>lpad(king,4,'-')
which means king should be padded with 4'-'
You need to include the length of the field because you have to allow for the number of characters in that, plus the amount of indentation you want. Taking the third-level Greenberg for example, that is displayed as:
____Greenberg
... with four underscores. Level is 3 here, so (level * 2) - 2 is four. But if you only used that value you'd get:
lpad('Greenberg', 4, '_')
and the output of that is just:
Gree
You want the final output string, including the underscores, to be four characters longer than the name on its own. 'Greenberg' is 9 characters, and ____Greenberg is 13; so your padding length has to be 13, which is the length of the name plus the number of underscores you want to appear in front.
Another way to get the same effect is with:
SELECT LPAD('_', (LEVEL - 1) * 2, '_') || last_name AS org_chart
...
That makes the underscore padding separate from the name itself - it's based just on the level, and the name is just concatenated on the end.
For King, the level is 1. You said the formula is:
lpad(king,4+(l*10)-10,'-')=>lpad(king,4,'-')
Which is right, but 'King' is already four characters long, so padding it out to four characters has no effect. Your are padding it out to the final length of 4. lpad doesn't add four underscores regardless; it only adds underscores up to the requested length, which is 4 in this case.
I think you're just misinterpreting how the function workd. As the documentation says (emphasis added):
LPAD returns expr1, left-padded to length n characters with the
sequence of characters in expr2.
...
The argument n is the total length of the return value as it is displayed on your terminal screen.
So:
select lpad('King',4,'_') from dual;
LPAD('KING',4,'_')
------------------
King
If you asked for a longer final length you'd get the number of underscores needed to pad 'King' out to that length:
select lpad('King',5,'_') from dual;
LPAD('KING',5,'_')
------------------
_King
If you want King to be indented as well, by two underscores; and subsequent levels to be indented more to match (so Kochhar gets 4 and Greenberg gets 6) then remove the -2 from the calculation.