Add String in a String before ".extention"? - sql

I have a table like:
ID NAME
----------------
35 File.png
What I want to do is update that record as:
ID NAME
----------------
35 File_35.png
I have this:
DECLARE arch_cursor CURSOR FOR SELECT Id from dbo.Archivos WHERE Nombre LIKE ('%' + #Id_Relacion_Articulo_Archivo + '%')
OPEN contact_cursor;
FETCH NEXT FROM arch_cursor
INTO #Id_cur
WHILE(##FETCH_STATUS = 0 )
UPDATE dbo.Archivos SET Nombre ...
CLOSE arch_cursor;
DEALLOCATE arch_cursor;
I know that STUFF statement can do something like put a string on a specific place of the string, but somebody know how to specify "insert string before "." without losing the left chars too?"

select id
, concat(left(name, charindex('.', name)-1), '_', id, RIGHT(name,(CHARINDEX('.', name))-1)) NAME
from test
Here is a demo
Also you can do it with a replace:
select id
, replace(name, '.', concat('_',id,'.'))
from test
And here is the one option you can use if you will look from the right (first occurrence of the character '.'):
select id
, concat(substring(name, 1, len(name)-charindex('.', (reverse(name))))
, '_'
, id
, substring(name, len(name)-charindex('.', (reverse(name)))+1, charindex('.', (reverse(name)))))
from test
Here is a demo where you can see all 3 of this examples in action with this two rows of data:
insert into test values (35, 'File.png')
insert into test values (55,
'File.File.png')

If no files can have a . in the name (apart from to denote the extension) I find STUFF easiest for this:
SELECT ID, [Name],
STUFF([Name], CHARINDEX('.',[Name]),0,CONCAT('_',ID)) AS NewName
FROM (VALUES(35,'File.png'))V(ID,[Name]);
If there could be multiple . characters and it needs to prior to the last one, you have to use the (expensive) function REVERSE:*
SELECT ID, [Name],
STUFF([Name], LEN([Name]) - CHARINDEX('.',REVERSE([Name]))+1,0,CONCAT('_',ID)) AS NewName
FROM (VALUES(35,'File.png'),(36,'File.2.png'))V(ID,[Name])
Also, don't loop. Just do this in a set based method. You're using a RDBMS, not a Programming Language:
UPDATE dbo.YourTable
SET File = STUFF([Name], CHARINDEX('.',[Name]),0,CONCAT('_',ID));

Related

Replace part of string in SQL

I got thousand of strings that contains data and with id's that is marked with a '#xx'. If the string has a '|' it menas that there is more data with an ID.
How do I find and replace all ID's that contains a specific ID? If I want to change #1 to #24 I don't want #11 to be changed to #241
Some exampels with expected output:
21600-39600#1 -> 21600-39600#24
21600-39600#2 -> 21600-39600#2
21600-39600#7|39600-52200#11|68000-72200#1 -> 21600-39600#7|39600-52200#11|68000-72200#24
Replace(column, '#1', '#24') will not work because #11 will be changed to #241. So I need to know if it is the end of the string or if it ends with an '|'
Quick and dirty but you could just do something like:
-- Update the end bits
UPDATE table
SET field = LEFT('field', LEN('field') -2) + '#24'
WHERE field LIKE '%#1';
-- Update the in between bits
UPDATE table
SET field = REPLACE(field, '#1|', '#24|')
WHERE field LIKE '%#1|%'; -- This where statement is optional due to the nature of the REPLACE.
Otherwise you'll have to look into the magical world of REGEX. If this is something you'd want to run more than once, I'd surely look into that. If this is just a one-time-fix-thingy, meh. It's thursday, I'd call it a valid excuse.
Try this
declare #t table(col varchar(100))
insert into #t
select '21600-39600#1' union all
select '21600-39600#2' union all
select '21600-39600#7|39600-52200#11|68000-72200#1'
select col,case when new_col like '%|' then
substring(new_col,1,len(new_col)-1)
else
new_col end as new_col
from
(
select col,
case when col+'|' like '%#1|%' then
Replace(col+'|', '#1|', '#24|') else col end as new_col
from #t
) as t
Result
col new_col
--------------------------------------------- ------------
21600-39600#1 21600-39600#24
21600-39600#2 21600-39600#2
21600-39600#7|39600-52200#11|68000-72200#1 21600-39600#7|39600-52200#11|68000-72200#24

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)

SQL substring from a string

I have a table XYZ with column FileName which has values as follows:
CCA_Type-PROPOSAL_Id-45845_Test1.txt
CPA_Type-PROPOSAL_Id-490845_Test2.txt
I want to update this column so that it contains only the filename and remove other characters preceeding:
Test1.txt
Test2.txt
Hence I wrote the following:
Update XYZ
set FileName = (select RIGHT(FileName,CHARINDEX('_',REVERSE(FileName),0)-1))
But if a FileName has a value like:
CCA_Type-PROPOSAL_Id-45845_Test_RR1.txt
My script returns RR1.txt instead of Test_RR1.txt! It finds the last underscore and returns substring from there. How can I change it so that I get the 3rd underscore and return a substring following it!
charindex optionally takes a start location. You could chain several together:
select right(FileName, len(FileName) -
charindex('_', FileName,
charindex('_', FileName,
charindex('_', FileName)
+ 1)
+ 1))
So you're asking for "The first underscore after (the first underscore after (the first underscore))" - i.e. the third underscore.
something like this should work:
declare #table table (
[file_name] [sysname]
);
declare #pattern [sysname]= N'_test';
insert into #table
([file_name])
values (N'CCA_Type-PROPOSAL_Id-45845_Test1.txt'),
(N'CPA_Type-PROPOSAL_Id-490845_Test2.txt'),
(N'CCA_Type-PROPOSAL_Id-45845_Test_RR1.txt');
select [file_name] as [file_name]
, charindex(#pattern, lower([file_name])) as [character_index_of_pattern]
, substring([file_name], charindex(#pattern, lower([file_name])), len([file_name])) as [desired_output]
from #table;

SQL Server - Select column that contains query string and split values into anothers 'columns'

I need to do a select in a column that contains a query string like:
user_id=300&company_id=201503&status=WAITING OPERATION&count=1
I want to perform a select and break each value in a new column, something like:
user_id | company_id | status | count
300 | 201503 | WAITING OPERATION | 1
How can i do it in SQL Server without use procs?
I've tried a function:
CREATE FUNCTION [xpto].[SplitGriswold]
(
#List NVARCHAR(MAX),
#Delim1 NCHAR(1),
#Delim2 NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
SELECT
Val1 = PARSENAME(Value,2),
Val2 = PARSENAME(Value,1)
FROM
(
SELECT REPLACE(Value, #Delim2, '&') FROM
(
SELECT LTRIM(RTRIM(SUBSTRING(#List, [Number],
CHARINDEX(#Delim1, #List + #Delim1, [Number]) - [Number])))
FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
FROM sys.all_objects) AS x
WHERE Number <= LEN(#List)
AND SUBSTRING(#Delim1 + #List, [Number], LEN(#Delim1)) = #Delim1
) AS y(Value)
) AS z(Value)
);
GO
Execution:
select QueryString
from User.Log
CROSS APPLY notifier.SplitGriswold(REPLACE(QueryString, ' ', N'ŏ'), N'ŏ', '&') AS t;
But it returns me only one column with all inside:
QueryString
user_id=300&company_id=201503&status=WAITING OPERATION&count=1
Thanks in advance.
I've had to do this many times before, and you're in luck! Since you only have 3 delimiters per string, and that number is fixed, you can use SQL Server's PARSENAME function to do it. That's far less ugly than the best alternative (using the XML parsing stuff). Try this (untested) query (replace TABLE_NAME and COLUMN_NAME with the appropriate names):
SELECT
PARSENAME(REPLACE(COLUMN_NAME,'&','.'),1) AS 'User',
PARSENAME(REPLACE(COLUMN_NAME,'&','.'),2) AS 'Company_ID',
PARSENAME(REPLACE(COLUMN_NAME,'&','.'),3) AS 'Status',
PARSENAME(REPLACE(COLUMN_NAME,'&','.'),4) AS 'Count',
FROM TABLE_NAME
That'll get you the results in the form "user_id=300", which is far and away the hard part of what you want. I'll leave it to you to do the easy part (drop the stuff before the "=" sign).
NOTE: I can't remember if PARSENAME will freak out over the illegal name character (the "=" sign). If it does, simply nest another REPLACE in there to turn it into something else, like an underscore.
You need to use SQL SUBSTRING as part of your select statement. You would first need to build the first row, then use a UNION to return the second row.

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