SQL-Server: Replace except first and last characters - sql

Is there any ways to SELECT the first and last 2 characters and REPLACE all the other characters with * as shown below?
WA***RT
EX*** ***IL
CH***ON
BE******* *****AY
AP*LE
Thanks in advance!

Spaces skipped:
SELECT
name,
[hidden] = CASE WHEN LEN(name) <= 4 THEN name
ELSE CONCAT(LEFT(name, 2),REPLICATE('*', LEN(name)- 2),RIGHT(name,2))
END
FROM #tab;
If you need spaces and there is only one you can use:
SELECT name,
[hidden] = CASE
WHEN LEN(name) <= 4 THEN name
WHEN CHARINDEX(' ', name) > 0
THEN STUFF(CONCAT(LEFT(name, 2),REPLICATE('*', LEN(name) - 2) ,
RIGHT(name,2)), CHARINDEX(' ', name),1, ' ')
ELSE CONCAT(LEFT(name, 2),REPLICATE('*', LEN(name) - 2) ,RIGHT(name,2))
END
FROM #tab;
LiveDemo
If you use version lower than SQL Server 2012 concatenate string with +.

select left(col, 2) + REPLICATE('*',len(col)-4) + right(col,2) from table;

You can use STUFF.
SELECT STUFF(col, 3, LEN(col)-4, REPLICATE('*',LEN(col)-4))
This doesn't preserve spaces.
To preserve N spaces, you can simply "add back spaces" with STUFF again:
SELECT col,
masked =
coalesce(
-- handle 2 spaces
STUFF(STUFF(
STUFF(col, 3, LEN(col)-4, REPLICATE('*',LEN(col)-4)),
CHARINDEX(' ', col), 1, ' '),
CHARINDEX(' ', col, CHARINDEX(' ', col)+1), 1, ' '),
-- handle 1 spaces
STUFF(
STUFF(col, 3, LEN(col)-4, REPLICATE('*',LEN(col)-4)),
CHARINDEX(' ', col), 1, ' '),
-- normal masking
STUFF(col, 3, LEN(col)-4, REPLICATE('*',LEN(col)-4)),
-- too short to mask
col
)
Demo

Related

How to get the first letter of each word in SQL

I tried to run this query to get the initial letter of each word, and it worked for strings of 4 words, yet if the string has only two words, it duplicates the second word's initial.
select
substring(column_name, 1, 1) +
case
when 0 <> charindex(' ', column_name) + 1
then substring(column_name, charindex(' ',column_name) + 1, 1)
else ''
end +
case
when 0 <> charindex(' ', column_name, charindex(' ', column_name) + 1)
then substring(column_name, charindex(' ', column_name, charindex(' ', column_name) + 1) + 1, 1)
else ''
end +
case
when 0 <> charindex(' ', column_name, charindex(' ', column_name, charindex(' ', column_name) + 1) + 1)
then substring(column_name, charindex(' ', column_name, charindex(' ', column_name, charindex(' ', column_name) + 1) + 1) + 1, 1)
else ''
end
from table_name
You didn't specify which RDBMS you are using. This should work in SQL Server:
drop table if exists table_name
create table table_name (
column_name varchar(255)
)
insert table_name
values ('See Jane')
, ('See Jane run')
, ('See Jane run and jump over the lazy dog.')
select stuff((SELECT '' + t2.fc
from (
select left(str.value, 1) fc
, charindex(' ' + str.value + ' ', ' ' + t.column_name + ' ') idx
from string_split(t.column_name, ' ') str
) t2
order by t2.idx
FOR XML PATH('')
), 1, 0, '') as FirstChars
from table_name t
The idx column is used to order the ouptut because string_split does not promise to return the results in any particular order. Thanks to Aaron Bertrand - https://dba.stackexchange.com/questions/207274/string-split-and-ordered-results
Given the use of charindex in your question, I'm assuming you are using SQL Server. The CTE generates a tall view of your data using string_split function, with each letter on it's own row. We then select from it and group by id, and apply the string_agg function to place back into a single row.
Password guessing?
create table my_data (
id integer,
comments varchar(50)
);
insert into my_data (id, comments) values
(1, 'Thank goodness its friday'),
(2, 'I want 2 scoops of ice cream');
select * from my_data;
id
comments
1
Thank goodness its friday
2
I want 2 scoops of ice cream
with cte (id, first_char) as (
select id, substring(ss.value, 1, 1) as first_char
from my_data
cross apply string_split(comments, ' ')ss
)
select t.id,
string_agg(t.first_char, ',') as letters_delimited,
string_agg(t.first_char, '') as letters_not_delimited
from cte t
group by t.id
id
letters_delimited
letters_not_delimited
1
T,g,i,f
Tgif
2
I,w,2,s,o,i,c
Iw2soic
fiddle here
You can extend your approach with recursion
WITH cte_name AS (
select CONVERT(nvarchar(max), substring(column_name, 1, 1)) conc,
column_name n,
charindex(' ', column_name, 0) pos
from table_name
UNION ALL
select conc + substring(n, pos + 1, 1) as conc,
n,
charindex(' ', n, pos + 1) pos
from cte_name where pos > 0
)
SELECT *
FROM cte_name
where pos = 0;

I'm having trouble separating the first name from the middle name column in SQL Server 2017

I created this syntax to separate first name, middle name and last name from a column called invertornames. Just to note that the investor names are in arabic and their middle names are more than 3 words. It worked fine but the first name is also being included in the middle name as you can see below in the image
This is the query I wrote:
SELECT
SUBSTRING(investor_name, CHARINDEX(', ', investor_name) + 2, CASE WHEN CHARINDEX(' ', investor_name, CHARINDEX(', ', investor_name) + 2) = 0 THEN LEN(investor_name) + 1 ELSE CHARINDEX(' ', investor_name, CHARINDEX(', ', investor_name) + 2) END - CHARINDEX(', ', investor_name) - 2)AS FirstName,
RTRIM(LTRIM(REPLACE(REPLACE(investor_name,SUBSTRING(investor_name , 1, CHARINDEX(' ', investor_name) -1),''),REVERSE( LEFT( REVERSE(investor_name), CHARINDEX(' ', REVERSE(investor_name))-1 ) ),''))) AS MiddleName,
RIGHT(investor_name, CHARINDEX(' ', REVERSE(investor_name))) AS LastName
FROM
investornames
If you need any data to try it please let me know.
You may try this. I consider that First word is considered as Firstname, second word is considered as MiddleName and remaining word will considered as LastName.
For the case of arabic names. Software will not automatically detect that for which name calculation start from the front and for which it is taken in reverse. So I guess you need to maintain a flag for same.
In case of arabic name in the portion of cte use reverse to arrange them in left to right order instead of right to left order. And at the end use reverse function again to convert them into their original state.
Hope I am clear about what I am explaining. Sample code is following :-
; with cte as (
select 'Deepak kumar singh' as names
union
select 'Deep'
union
select 'deep kumar'
union
select 'Deepak kumar singh chandel')
SELECT
Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 1)) As [FirstName]
, Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) As [MiddleName]
, case when len( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 3)))>0 then substring ( names ,
charindex ( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ', names) + len(Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ') + 1
, len(names) - charindex ( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ', names) + len(Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ')) else null end
As [LastName]
FROM (Select names from cte ) As [x]
Result of above query is:
FirstName MiddleName LastName
Deep NULL NULL
deep kumar NULL
Deepak kumar singh
deepak kumar singh chandel
Edit
Updated this ans check this
; with cte as (
select ' شركة عبدالمحسن عبدالعزيزالبابطين ' as names
union
select 'شركة'
union
select 'عبدالمحسن عبدالعزيز'
union
select 'البابطين')
, ct as (
select RTRIM(LTRIM(names)) as Names from cte )
SELECT
Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 1)) As [FirstName]
, Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) As [MiddleName]
, case when len( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 3)))>0 then substring ( names ,
charindex ( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ', names) + len(Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ') + 1
, len(names) - charindex ( Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ', names) + len(Reverse(ParseName(Replace(Reverse(names), ' ', '.'), 2)) + ' ')) else null end
As [LastName]
FROM (Select names from ct ) As [x]
Result
FirstName MiddleName LastName
???? ????????? ?????????????????
???? NULL NULL
???????? NULL NULL
????????? ????????? NULL
Here I am expecting on place of ? you'll get your result. BTW I've updated my query, have you tried this one. Just give one more try.

Trim extra white space within column

I have the following select that is converting a name from Lastname, Firstname format into Firstname Lastname format. It seems to be adding extra white space between the first name and the last name
SELECT substring(D.NAME, charindex(',', replace(D.NAME, ' ', '')) + 1, len(D.NAME))
+ ' '
+ left(D.NAME, charindex(',', D.NAME) -1) AS First_Last
FROM TEST_TABLE D
Here are a few examples of the output I'm getting now:
Johnnyyy Smithsonnn
Kimmey Test1
Denise Stuffing
Desired Format (single space between first and last name):
Johnnyyy Smithsonnn
Kimmey Test1
Denise Stuffing
I tend to like this technique. In this example we use a rare replacement pattern of †‡, but you can use <> and ><
Note: The outer ltrim(rtrim( ... )) is optional, I keep it as a "just in case".
Example
Select NewValue = ltrim(rtrim(replace(replace(replace([Name],' ','†‡'),'‡†',''),'†‡',' ')))
From YourTable
Returns
NewValue
Johnnyyy Smithsonnn
Kimmey Test1
Denise Stuffing
Maybe there are names with or without , or with or without spaces after the ,, or other inconsistencies.
Anyway you can use ltrim(rtrim()) before concatenating:
select
case
when d.name like '%,%' then
ltrim(rtrim(substring(d.name, charindex(',', name) + 1, len(d.name))))
+ ' ' +
ltrim(rtrim(left(D.NAME, charindex(',', d.name) -1)))
when d.name like '% %' then
ltrim(rtrim(substring(d.name, charindex(' ', name) + 1, len(d.name))))
+ ' ' +
ltrim(rtrim(left(D.NAME, charindex(' ', d.name) -1)))
else ltrim(rtrim(d.name))
end AS First_Last
Try:
select ltrim(rtrim(left(D.NAME, charindex(',', D.NAME, 0) - 1)))
+ ' '
+ ltrim(rtrim(right(D.NAME, len(D.NAME) - charindex(',', D.NAME, 0))))
from TEST_TABLE D
This worked on some test data I used below:
insert into #Test ([Name]) values ('Johnnyyy, Smithsonnn')
insert into #Test ([Name]) values ('Kimmey, Test1')
insert into #Test ([Name]) values ('Denise, Stuffing')
Which gives the intended result:
Johnnyyy Smithsonnn
Kimmey Test1
Denise Stuffing
I think you intend to do the replace of spaces after extracting the name. So:
SELECT (replace(left(D.NAME, charindex(',', D.NAME + ',') + 1), ' ', '') +
' ' +
left(D.NAME, charindex(',', D.NAME + ',') - 1)
) AS First_Last
FROM TEST_TABLE D;
This also adds a comma for the charindex() so the comma is optional.

Extracting first word from a string in SQL, where the string is a single word

I am able to extract the first word from a string, using ANSI SQL, like this:
SELECT SUBSTRING(name FROM 1 FOR POSITION(' ' IN name)) AS first_name
However, if the original string is only one word long (ie, if there is no space), it returns an empty substring.
How can the above query be adapted to solve this problem?
Thanks in advance.
I'm sure there is a cleaner way to do it, but this works.
DECLARE #tbl TABLE (i varchar(100));
INSERT INTO #tbl ( i )
VALUES ('hello'), ('hello space here');
SELECT *,
SUBSTRING(i, 0, CASE CHARINDEX(' ', i)
WHEN 0 THEN LEN(i) + 1
ELSE CHARINDEX(' ', i)
END)
FROM #tbl
Simply but messy solution - add a space on the end:
SELECT SUBSTRING((name || ' ') FROM 1 FOR POSITION(' ' IN (name || ' '))) AS first_name
Use a conditional if statement.
For a MySQL/SQL Server answer:
SELECT IF(INSTR(name, ' ') >0, LEFT(name, INSTR(name, ' ') - 1), name) AS firstname
For Oracle:
SELECT IF(INSTRB(name, ' ', 1, 1) >0, SUBSTR(name, 1, INSTRB(name, ' ', 1, 1) - 1), name) AS firstname
I personally prefer the Regexp query for this, but below query also works.
You basically append a space at the end of the string and search for the position of the space using INSTR.
ORACLE:
select substr(Var1, 0,INSTR(Var1||' ',' ')) from table-name;
Replace Var1 with the column-name or string you are evaluating.
Put Column Name in place of #foo
DECLARE #Foo VARCHAR(50) = 'One Two Three'
SELECT
CASE
--For One Word
WHEN CHARINDEX(' ', #Foo, 1) = 0 THEN #Foo
--For multi word
ELSE SUBSTRING(#Foo, 1, CHARINDEX(' ', #Foo, 1) - 1)
END
DECLARE #test VARCHAR(50) = 'One Two Three'
SELECT SUBSTRING(LTRIM(#test),1,(CHARINDEX(' ',LTRIM(#test) + ' ')-1))
you can use this to get the first word of a string.initcap
will get you the first letter capital.
SELECT SUBSTR(column_1, 1, INSTR(column_1, ' ', 1,1) ) FROM table_name WHERE column_1= initcap('your string');

TSQL - Locating first occurrence of value in a string

I need to run a simple select statement for a column called AddrZip to show all records that contain '1/2 ' after the first space in the column. In Access 2007 it would be: **Left([Names],InStr(1,[Names]," ")-1), but can't find out how to do it in SQL 2005. All help will be appreciated.
First, look for records with a ' ':
CHARINDEX(' ', [AddrZip]) > 0
Then look for records with a '1/2' occurring after the ' '
CHARINDEX('1/2', [AddrZip], CHARINDEX(' ', [AddrZip])) > 0
SELECT *
FROM ( SELECT *
FROM [Addresses]
WHERE CHARINDEX(' ', [AddrZip]) > 0
) x
WHERE CHARINDEX('1/2', [x].[AddrZip], CHARINDEX(' ', [AddrZip])) > 0
This "simplified" version may work:
SELECT *
FROM [Addresses]
WHERE CHARINDEX(' ', [AddrZip]) > 0
AND CHARINDEX('1/2', [x].[AddrZip], CHARINDEX(' ', [AddrZip])) > 0
If you want to find occurrences of '1/2' that are immediately preceded by a ' ' where the ' ' is the very first space in the string, then use the following code:
SELECT *
FROM [Addresses]
WHERE CHARINDEX(' ', [AddrZip]) > 0
AND CHARINDEX(' ', [AddrZip]) = CHARINDEX(' 1/2', [x].[AddrZip])
Avoid LIKE operators if at all possible. They are notoriously slow.
Try this -
select * from table where addrZip like '%\ 1/2%' escape '\'