Retrieving right two words in char DB2 field - sql

Using SQL, how can I retrieve the 2 words from the right end of a CHAR(30) field?
namefield = "My name is Bill Smith"
results = Bill Smith

This is untested, but maybe something like:
SELECT REVERSE(SUBSTRING(REVERSE(namefield) , 0, CHARINDEX(' ', REVERSE(namefield), CHARINDEX(' ', REVERSE(namefield), 0)+1))) FROM TABLE
Replace table with your table. Let me know if it works!

If you use LOCATE_IN_STRING you can say -X to search backwards - as op. to charindex which only only look forward.
select
-- locate_in_string(str,' ',-1),
-- substr(str,1,locate_in_string(str,' ',-1)-1),
-- length(str) - locate_in_string(str,' ',-1),
-- locate_in_string(str,' ',-7),
-- locate_in_string(str,' ',(-1* (length(str) - locate_in_string(str,' ',-1))) -2 ),
-- substr(str,1,11) || '<-',
-- substr(str,1,locate_in_string(str,' ',(-1* (length(str) - locate_in_string(str,' ',-1))) -2 )-1),
substr(str,locate_in_string(str,' ',(-1* (length(str) - locate_in_string(str,' ',-1))) -2 ))
FROM (
VALUES('My name is Bill Smith')
) AS T(str)
Here I start at the point of the last space and search for the prior space and then pass that to substr.
https://www.ibm.com/support/knowledgecenter/en/SSEPGG_9.7.0/com.ibm.db2.luw.sql.ref.doc/doc/r0054098.html
I've included my testing code above -- you can see how I test various parts by removing the comment for that line. This technique my prove useful in your testing.

Related

Hide characters in email address using an SQL query

I have a very specific business requirement to hide certain characters within an email address when returned from SQL and I have hit the limit of my ability with SQL to achieve this. I was wondering if someone out there would be able to point me in the right direction. Essentially, my business is asking for the following:
test#email.com to become t*\*t#e**l.com
or
thislong#emailaddress.com to become t******h#e**********s.com
I am aware that if either portion of the email before of after the # are less than 3 characters, then this won't work, but I intend on checking for this and dealing with it appropriately. I have tried a mixture of SUBSTRING, STUFF, LEFT/RIGHT etc but I can't quite get it right.
DECLARE #String VARCHAR(100) = 'example#gmail.com'
SELECT LEFT(#String, 1) + '*****#'
+ REVERSE(LEFT(RIGHT(REVERSE(#String) , CHARINDEX('#', #String) +1), 1))
+ '******'
+ RIGHT(#String, 5)
result will be
e******e#g***l.com
Very interesting and very much tough to generate generic solution try this
this may help you
DECLARE #String VARCHAR(100) = 'sample#gmail.com'
SELECT STUFF(STUFF(#STring,
CHARINDEX('#',#String)+2,
(CHARINDEX('.',#String, CHARINDEX('#',#String))-CHARINDEX('#',#String)-3),
REPLICATE('*',CHARINDEX('.',#String, CHARINDEX('#',#String))-CHARINDEX('#',#String)))
,2
,CHARINDEX('#',#String)-3
,REPLICATE('*',CHARINDEX('#',#String)-3))
OUTPUT will be
s****e#g******l.com
Similar way for thislong#emailaddress.com
OUTPUT will be
t******g#e*************s.com
You could also use regular expressions. Something like this (not completely finished):
select regexp_replace('test#email.com', '^(.?).*#(.?).*', '\1***#\2***')
from dual
Results in:
t***#e***
Could be a useful solution if you can only use SELECT statements.
CREATE FUNCTION dbo.EmailObfuscate
( #Email VARCHAR(255)
) RETURNS TABLE AS RETURN
(
SELECT adr.email
, LEFT (adr.email, 1)
+ REPLICATE ('*', AtPos-3)
+ SUBSTRING (adr.Email, AtPos-1, 3)
+ REPLICATE ('*', Length-DotPos - AtPos - 2)
+ SUBSTRING (adr.Email, Length - DotPos, 10) AS hide
FROM ( VALUES ( #Email) ) AS ADR (EMail)
CROSS APPLY ( SELECT CHARINDEX ('#', adr.Email)
, CHARINDEX ('.', REVERSE(Adr.Email))
, LEN (Adr.Email)
) positions ( AtPos
, dotpos
, Length
)
);
GO
-- Calling
SELECT Emails.*
FROM ( Values ( 'this.long#emailaddress.com')
, ( 'test#email.com' )
, ( 'sample#gmail.com' )
, ( 'test#gmx.de' )
) AS adr (email)
CROSS APPLY dbo.EmailObfuscate (Adr.Email) AS Emails
SELECT
-- Email here is the name of the selected Column from your Table
--Display the First Character
SUBSTRING(Email,1,1)+
--Replace selected Number of *
REPLICATE('*',10)+
--Display the One Character before # along with # & One Character after #
SUBSTRING(Email,CHARINDEX('#',Email)-1,3)+
--Replace selected Number of *
REPLICATE('*',10)+
--Display. Character along with the rest selected Number of Characters
SUBSTRING(Email,CHARINDEX('.',Email)-1, LEN(Email) -
CHARINDEX('.',Email)+12)
--NameEmail is the Table Name
FROM NameEmail
Result is:
j**********l#a**********a.co.uk
I've found this answer, but was searching for PostgreSQL version (and have not found it)
So I've made my own for PGSQL
SELECT
-- Email here is the name of the selected Column from your Table
--Display the First Character
SUBSTRING('g40gj30m#my-email.co.uk', 1, 1) ||
--Replace selected Number of *
REPEAT('*', 10) ||
--Display the One Character before # along with # & One Character after #
SUBSTRING('g40gj30m#my-email.co.uk', strpos('g40gj30m#my-email.co.uk', '#') - 1, 3) ||
--Replace selected Number of *
REPEAT('*', 10) ||
--Display. Character along with the rest selected Number of Characters
SUBSTRING(
'g40gj30m#my-email.co.uk',
strpos('g40gj30m#my-email.co.uk', '.') - 1,
length('g40gj30m#my-email.co.uk') - strpos('g40gj30m#my-email.co.uk', '.') + 12
);
the result will be
?column?
---------------------------------
g**********m#m**********l.co.uk
(1 row)

Extract value between two characters with varying positions

NOTE: I am using TSQL
I need to be able to extract data from the middle of a string. Both the length of the data I need, and the length of the string will vary.
Here are examples of the complete string:
362 Any Rd - NewPc#:420010079274892700465647513335 - StopID:12345
362 Any Rd - NewPc#:4200644392748927004720180006426006 - StopID:12345
362 Any Rd - NewPc#:00006675214112593057 - StopID:12345
362 Random Rd - NewPc#:420063709274892700465647550149 - StopID:4567
I only need the following from the above strings:
420010079274892700465647513335
4200644392748927004720180006426006
00006675214112593057
420063709274892700465647550149
Can someone please help me figure this out?
You can use a combination of substring and charindex.
Fiddle
select
substring(somecolumn, charindex(':',somecolumn) + 1,
len(somecolumn) -
charindex('-', reverse(somecolumn)) - 1 - charindex(':',somecolumn))
from tablename
Select SUBSTRING( Note,CHARINDEX ('#:' , Note, 1 ) +2,
CHARINDEX ( ' - S' ,Note ,1 )-
CHARINDEX ('#:' , Note, 1 ) -2 )
from OER
You use 2 functions for your table oer:
1st is to find the location for ":"
CHARINDEX ('#:' , Note, 1 ) +2
The +2 is to get rid of the "#:"
You need to use this 2 times, once again for the " - S" To see how many characters you want to go.
CHARINDEX ( ' - S' ,Note ,1 )
And the 2nd function is Substring to use part of your Note
link sql fiddle:
http://sqlfiddle.com/#!3/95ce8/7/0
An example is this: You have a string and the character $
String :
aaaaa$bbbbb$ccccc
Code:
SELECT SUBSTRING('aaaaa$bbbbb$ccccc',CHARINDEX('$','aaaaa$bbbbb$ccccc')+1, CHARINDEX('$','aaaaa$bbbbb$ccccc',CHARINDEX('$','aaaaa$bbbbb$ccccc')+1) -CHARINDEX('$','aaaaa$bbbbb$ccccc')-1) as My_String
Output:
bbbbb

Parse column value based on delimeters

Here is a sample of my data:
ABC*12345ABC
BCD*234()
CDE*3456789(&(&
DEF*4567A*B*C
Using SQL Server 2008 or SSIS, I need to parse this data and return the following result:
12345
234
3456789
4567
As you can see, the asterisk (*) is my first delimiter. The second "delimiter" (I use this term loosely) is when the sequence of numbers STOP.
So, basically, just grab the sequence of numbers after the asterisk...
How can I accomplish this?
EDIT:
I made a mistake in my original post. An example of another possible value would be:
XWZ*A12345%$%
In this case, I would like to return the following:
A12345
The value can START with an alpha character, but it will always END with a number. So, grab everything after the asterisk, but stop at the last number in the sequence.
Any help with this will be greatly appreciated!
You could do this with a little patindex and charindex trickery, like:
; with YourTable(col1) as
(
select 'ABC*12345ABC'
union all select 'BCD*234()'
union all select 'CDE*3456789(&(&'
union all select 'DEF*4567A*B*C'
union all select 'XWZ*A12345%$%'
)
select left(AfterStar, len(Leader) + PATINDEX('%[^0-9]%', AfterLeader) - 1)
from (
select RIGHT(AfterStar, len(AfterStar) - PATINDEX('%[0-9]%', AfterStar) + 1)
as AfterLeader
, LEFT(AfterStar, PATINDEX('%[0-9]%', AfterStar) - 1) as Leader
, AfterStar
from (
select RIGHT(col1, len(col1) - CHARINDEX('*', col1)) as AfterStar
from YourTable
) as Sub1
) as Sub2
This prints:
12345
234
3456789
4567
A12345
If you ignore that this is in SQL then the first thing that comes to mind is Regex:
^.*\*(.*[0-9])[^0-9]*$
The capture group there should get what you want. I don't know if SQL has a regex function.

Oracle SQL - Parsing a name string and converting it to first initial & last name

Does anyone know how to turn this string: "Smith, John R"
Into this string: "jsmith" ?
I need to lowercase everything with lower()
Find where the comma is and track it's integer location value
Get the first character after that comma and put it in front of the string
Then get the entire last name and stick it after the first initial.
Sidenote - instr() function is not compatible with my version
Thanks for any help!
Start by writing your own INSTR function - call it my_instr for example. It will start at char 1 and loop until it finds a ','.
Then use as you would INSTR.
The best way to do this is using Oracle Regular Expressions feature, like this:
SELECT LOWER(regexp_replace('Smith, John R',
'(.+)(, )([A-Z])(.+)',
'\3\1', 1, 1))
FROM DUAL;
That says, 1) when you find the pattern of any set of characters, followed by ", ", followed by an uppercase character, followed by any remaining characters, take the third element (initial of first name) and append the last name. Then make everything lowercase.
Your side note: "instr() function is not compatible with my version" doesn't make sense to me, as that function's been around for ages. Check your version, because Regular Expressions was only added to Oracle in version 9i.
Thanks for the points.
-- Stew
instr() is not compatible with your version of what? Oracle? Are you using version 4 or something?
There is no need to create your own function, and quite frankly, it seems a waste of time when this can be done fairly easily with sql functions that already exist. Care must be taken to account for sloppy data entry.
Here is another way to accomplish your stated goal:
with name_list as
(select ' Parisi, Kenneth R' name from dual)
select name
-- There may be a space after the comma. This will strip an arbitrary
-- amount of whitespace from the first name, so we can easily extract
-- the first initial.
, substr(trim(substr(name, instr(name, ',') + 1)), 1, 1) AS first_init
-- a simple substring function, from the first character until the
-- last character before the comma.
, substr(trim(name), 1, instr(trim(name), ',') - 1) AS last_name
-- put together what we have done above to create the output field
, lower(substr(trim(substr(name, instr(name, ',') + 1)), 1, 1)) ||
lower(substr(trim(name), 1, instr(trim(name), ',') - 1)) AS init_plus_last
from name_list;
HTH,
Gabe
I have a hard time believing you don’t have access to a proper instr() but if that’s the case, implement your own version.
Assuming you have that straightened out:
select
substr(
lower( 'Smith, John R' )
, instr( 'Smith, John R', ',' ) + 2
, 1
) || -- first_initial
substr(
lower( 'Smith, John R' )
, 1
, instr( 'Smith, John R', ',' ) - 1
) -- last_name
from dual;
Also, be careful about your assumption that all names will be in that format. Watch out for something other than a single space after the comma, last names having data like “Parisi, Jr.”, etc.

Uppercase first two characters in a column in a db table

I've got a column in a database table (SQL Server 2005) that contains data like this:
TQ7394
SZ910284
T r1534
su8472
I would like to update this column so that the first two characters are uppercase. I would also like to remove any spaces between the first two characters. So T q1234 would become TQ1234.
The solution should be able to cope with multiple spaces between the first two characters.
Is this possible in T-SQL? How about in ANSI-92? I'm always interested in seeing how this is done in other db's too, so feel free to post answers for PostgreSQL, MySQL, et al.
Here is a solution:
EDIT: Updated to support replacement of multiple spaces between the first and the second non-space characters
/* TEST TABLE */
DECLARE #T AS TABLE(code Varchar(20))
INSERT INTO #T SELECT 'ab1234x1' UNION SELECT ' ab1234x2'
UNION SELECT ' ab1234x3' UNION SELECT 'a b1234x4'
UNION SELECT 'a b1234x5' UNION SELECT 'a b1234x6'
UNION SELECT 'ab 1234x7' UNION SELECT 'ab 1234x8'
SELECT * FROM #T
/* INPUT
code
--------------------
ab1234x3
ab1234x2
a b1234x6
a b1234x5
a b1234x4
ab 1234x8
ab 1234x7
ab1234x1
*/
/* START PROCESSING SECTION */
DECLARE #s Varchar(20)
DECLARE #firstChar INT
DECLARE #secondChar INT
UPDATE #T SET
#firstChar = PATINDEX('%[^ ]%',code)
,#secondChar = #firstChar + PATINDEX('%[^ ]%', STUFF(code,1, #firstChar,'' ) )
,#s = STUFF(
code,
1,
#secondChar,
REPLACE(LEFT(code,
#secondChar
),' ','')
)
,#s = STUFF(
#s,
1,
2,
UPPER(LEFT(#s,2))
)
,code = #s
/* END PROCESSING SECTION */
SELECT * FROM #T
/* OUTPUT
code
--------------------
AB1234x3
AB1234x2
AB1234x6
AB1234x5
AB1234x4
AB 1234x8
AB 1234x7
AB1234x1
*/
UPDATE YourTable
SET YourColumn = UPPER(
SUBSTRING(
REPLACE(YourColumn, ' ', ''), 1, 2
)
)
+
SUBSTRING(YourColumn, 3, LEN(YourColumn))
UPPER isn't going to hurt any numbers, so if the examples you gave are completely representative, there's not really any harm in doing:
UPDATE tbl
SET col = REPLACE(UPPER(col), ' ', '')
The sample data only has spaces and lowercase letters at the start. If this holds true for the real data then simply:
UPPER(REPLACE(YourColumn, ' ', ''))
For a more specific answer I'd politely ask you to expand on your spec, otherwise I'd have to code around all the other possibilities (e.g. values of less than three characters) without knowing if I was overengineering my solution to handle data that wouldn't actually arise in reality :)
As ever, once you've fixed the data, put in a database constraint to ensure the bad data does not reoccur e.g.
ALTER TABLE YourTable ADD
CONSTRAINT YourColumn__char_pos_1_uppercase_letter
CHECK (ASCII(SUBSTRING(YourColumn, 1, 1)) BETWEEN ASCII('A') AND ASCII('Z'));
ALTER TABLE YourTable ADD
CONSTRAINT YourColumn__char_pos_2_uppercase_letter
CHECK (ASCII(SUBSTRING(YourColumn, 2, 1)) BETWEEN ASCII('A') AND ASCII('Z'));
#huo73: yours doesn't work for me on SQL Server 2008: I get 'TRr1534' instead of 'TR1534'.
update Table set Column = case when len(rtrim(substring (Column , 1 , 2))) < 2
then UPPER(substring (Column , 1 , 1) + substring (Column , 3 , 1)) + substring(Column , 4, len(Column)
else UPPER(substring (Column , 1 , 2)) + substring(Column , 3, len(Column) end
This works on the fact that if there is a space then the trim of that part of string would yield length less than 2 so we split the string in three and use upper on the 1st and 3rd char. In all other cases we can split the string in 2 parts and use upper to make the first two chars to upper case.
If you are doing an UPDATE, I would do it in 2 steps; first get rid of the space (RTRIM on a SUBSTRING), and second do the UPPER on the first 2 chars:
// uses a fixed column length - 20-odd in this case
UPDATE FOO
SET bar = RTRIM(SUBSTRING(bar, 1, 2)) + SUBSTRING(bar, 3, 20)
UPDATE FOO
SET bar = UPPER(SUBSTRING(bar, 1, 2)) + SUBSTRING(bar, 3, 20)
If you need it in a SELECT (i.e. inline), then I'd be tempted to write a scalar UDF