need to replace some underscores with hypens - sql

I have a column with value
AAA_ZZZZ_7890_10_28_2014_123456.jpg
I need to replace the middle underscores so that it displays it as date i.e.
AAA_ZZZZ_7890_10-28-2014_123456.jpg
Can some one please suggest a simple update query for this.
The Number of Underscores would be same for all the values in the column but the length will vary for example some can have
AAA_q10WRQ_001_10_28_2014_12.jpg

The following should do it:
http://sqlfiddle.com/#!3/d41d8/30384/0
declare #filename varchar(64) = 'AAA_ZZZZ_7890_10_28_2014_123456.jpg'
declare #datepattern varchar(64) = '%[_][0-1][0-9][_][0-3][0-9][_][1-2][0-9][0-9][0-9][_]%'
select
filename,
substring(filename,1,datepos+2)+'-'+
substring(filename,datepos+4,2)+'-'+
substring(filename,datepos+7,1000)
from
(
select
#filename filename,
patindex(#datepattern,#filename)
as datepos
) t
;
Resulting in
AAA_ZZZZ_7890_10-28-2014_123456.jpg
Caveats to watch out for:
It is important to exactly define how you find the date. In my definition it is MM_DD_YYYY surrounded by further two underscores, and I check that the first digits of M,D,Y are 0-1,0-3,1-2 respectively (i.e. I do NOT check if month is e.g. 13.) -- of course we assume that there is only one such string in any file name.
datepos actually finds the position of the underscore before the date -- this is not an issue if taken into account in the indexing of substring.
in the 3rd substring the length cannot be NULL or infinity and I couldn't get LEN() to work in SQL Fiddle so I dirty hardcoded a large enough number (1000). Corrections to this are welcome.

Try this (assuming that the DATE portion always starts at the same character index)
declare #string varchar(64) = 'AAA_ZZZZ_7890_10_28_2014_123456.jpg'
select replace(#string, reverse(substring(reverse(#string), charindex('_', reverse(#string), 0) + 1, 10)), replace(reverse(substring(reverse(#string), charindex('_', reverse(#string), 0) + 1, 10)), '_', '-'))

If there are exactly 6 _ then for the first
select STUFF ( 'AAA_ZZZZ_7890_10_28_2014_123456.jpg' , CHARINDEX ( '_' ,'AAA_ZZZZ_7890_10_28_2014_123456.jpg', CHARINDEX ( '_' ,'AAA_ZZZZ_7890_10_28_2014_123456.jpg', CHARINDEX ( '_' ,'AAA_ZZZZ_7890_10_28_2014_123456.jpg', CHARINDEX ( '_' ,'AAA_ZZZZ_7890_10_28_2014_123456.jpg', 0 ) + 1 ) + 1 ) + 1 ) , 1 , '-' )

Related

How to create a function to split date and time from a string in SQL?

How can I remove value before '_' and show date and time in one row in TSQL Function?
Below is sample:
Declare #inputstring as varchar(50) = 'Studio9_20230126_203052' ;
select value from STRING_SPLIT( #inputstring ,'_')
Output Required: 2023-01-26 20:30:52.000
If we can safely assume that the value is always in the format {Some String}_{yyyyMMdd}_{hhmmss} then you can use STUFF a few times, firstly to remove the leading string up to the first underscore (_) character (using CHARINDEX to find that character), and then to inject 2 colon (:) characters. Finally you can REPLACE the remaining underscore with a space ( ), and then use TRY_CONVERT to attempt to convert the value to a datetime2(0).
DECLARE #inputstring varchar(50) = 'Studio9_20230126_203052';
SELECT TRY_CONVERT(datetime2(0),REPLACE(STUFF(STUFF(STUFF(#inputstring,1,CHARINDEX('_',#inputstring),''),14,0,':'),12,0,':'),'_',' '));
Note that this doesn't give the value you state you want in your question (2023-01-26 20:05:52.000) , but I assume this is a typographical error, and that the 05 for minutes should be 30.
Creating function
CREATE FUNCTION [dbo].[convert_to_date] (#inputstring NVARCHAR(MAX))
RETURNS DATETIME AS
BEGIN
DECLARE #finalString varchar(50), #out varchar(100)
SET #finalString = REPLACE ( (SUBSTRING (#inputstring, CHARINDEX('_', #inputstring)+1 , LEN(#inputstring))), '_', ' ')
--SELECT #finalString
SET #out = LEFT (#finalString, 4) + '-'
+ SUBSTRING(#finalString, 5, 2) + '-'
+ SUBSTRING(#finalString, 7, 2) + ' '
+ SUBSTRING(#finalString, 10, 2) + ':'
+ SUBSTRING(#finalString, 12, 2) + ':'
+ SUBSTRING(#finalString, 14, 2) + '.000'
RETURN #out
END
Select Query
SELECT dbo.[convert_to_date] ('Studio54541659_20230126_203052')
Output
2023-01-26 20:30:52.000
This will tolerate "somestring" in the format of "somestring_YYYYMMDD_HHMISS" being variable in length.
Declare #inputstring as varchar(50) = 'Studio9_20230126_203052' ;
SELECT DateAndTime = CONVERT(DATETIME,STUFF(STUFF(STUFF(v2.DT,14,0,':'),12,0,':'),9,1,' '))
,Identifier = LEFT(#inputstring,v1.Pos1-1) --Included this because I know how people are :D --Comment out if not wanted.
,Original = #inputstring --Original string just for checking. Comment out when happy.
FROM (VALUES(CHARINDEX('_',#inputstring)))v1(Pos1) --Position of first Underscore
CROSS APPLY (VALUES(SUBSTRING(#inputstring,v1.Pos1+1,50)))v2(DT) --String after first Underscore
;
Output looks like this and you end up with a DATETIME datatype. Comment out what you don't want for columns in the return.
I'll let you have some of the fun by converting it into an iTVF (inline Table Valued Function). Remember that any function that contains a "BEGIN" is ultimately going to be a part of a performance issue so make sure it's an iTVF :D
EDIT: Crud... I've gotta remember to scroll down. #Lamu already posted the same thing but it's probably better and fast if you just want the time and not the identifier I included.

How to fix error with negative value being passed to LEFT()

The following is designed to extract the first chars from a string. In this case extracting the area from a postcode. As the area may be variable length (1 or 2 chars) the rule is get the first alpha characters, before the numbers in the first half of the string (delimited by a space).
If the string is formatted correctly, the following works. However, if the string is malformed (as demonstrated below) the PATINDEX returns 0, which in turn results in -1 being passed back to the parent LEFT().
How can I trap the negative value and substitute the -1 with a 0?
Malformations could take the format:
'ABO 12BT', 'AB012BT' etc.
DECLARE #Postcode nVARCHAR (10) = 'ab124th'
(
SELECT
RTRIM
(
LEFT
(
LEFT
(
#Postcode, CHARINDEX(' ', #Postcode)
),
(
PATINDEX
(
'%[0-9]%',
LEFT
(
#Postcode,
CHARINDEX(' ', #Postcode)
)
) -1
)
)
)
)
isnull(nullif(patnidex(...) - 1, -1), 0)

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)

How can I remove leading and trailing quotes in SQL Server?

I have a table in a SQL Server database with an NTEXT column. This column may contain data that is enclosed with double quotes. When I query for this column, I want to remove these leading and trailing quotes.
For example:
"this is a test message"
should become
this is a test message
I know of the LTRIM and RTRIM functions but these workl only for spaces. Any suggestions on which functions I can use to achieve this.
I have just tested this code in MS SQL 2008 and validated it.
Remove left-most quote:
UPDATE MyTable
SET FieldName = SUBSTRING(FieldName, 2, LEN(FieldName))
WHERE LEFT(FieldName, 1) = '"'
Remove right-most quote: (Revised to avoid error from implicit type conversion to int)
UPDATE MyTable
SET FieldName = SUBSTRING(FieldName, 1, LEN(FieldName)-1)
WHERE RIGHT(FieldName, 1) = '"'
I thought this is a simpler script if you want to remove all quotes
UPDATE Table_Name
SET col_name = REPLACE(col_name, '"', '')
You can simply use the "Replace" function in SQL Server.
like this ::
select REPLACE('this is a test message','"','')
note: second parameter here is "double quotes" inside two single quotes and third parameter is simply a combination of two single quotes. The idea here is to replace the double quotes with a blank.
Very simple and easy to execute !
My solution is to use the difference in the the column values length compared the same column length but with the double quotes replaced with spaces and trimmed in order to calculate the start and length values as parameters in a SUBSTRING function.
The advantage of doing it this way is that you can remove any leading or trailing character even if it occurs multiple times whilst leaving any characters that are contained within the text.
Here is my answer with some test data:
SELECT
x AS before
,SUBSTRING(x
,LEN(x) - (LEN(LTRIM(REPLACE(x, '"', ' ')) + '|') - 1) + 1 --start_pos
,LEN(LTRIM(REPLACE(x, '"', ' '))) --length
) AS after
FROM
(
SELECT 'test' AS x UNION ALL
SELECT '"' AS x UNION ALL
SELECT '"test' AS x UNION ALL
SELECT 'test"' AS x UNION ALL
SELECT '"test"' AS x UNION ALL
SELECT '""test' AS x UNION ALL
SELECT 'test""' AS x UNION ALL
SELECT '""test""' AS x UNION ALL
SELECT '"te"st"' AS x UNION ALL
SELECT 'te"st' AS x
) a
Which produces the following results:
before after
-----------------
test test
"
"test test
test" test
"test" test
""test test
test"" test
""test"" test
"te"st" te"st
te"st te"st
One thing to note that when getting the length I only need to use LTRIM and not LTRIM and RTRIM combined, this is because the LEN function does not count trailing spaces.
I know this is an older question post, but my daughter came to me with the question, and referenced this page as having possible answers. Given that she's hunting an answer for this, it's a safe assumption others might still be as well.
All are great approaches, and as with everything there's about as many way to skin a cat as there are cats to skin.
If you're looking for a left trim and a right trim of a character or string, and your trailing character/string is uniform in length, here's my suggestion:
SELECT SUBSTRING(ColName,VAR, LEN(ColName)-VAR)
Or in this question...
SELECT SUBSTRING('"this is a test message"',2, LEN('"this is a test message"')-2)
With this, you simply adjust the SUBSTRING starting point (2), and LEN position (-2) to whatever value you need to remove from your string.
It's non-iterative and doesn't require explicit case testing and above all it's inline all of which make for a cleaner execution plan.
The following script removes quotation marks only from around the column value if table is called [Messages] and the column is called [Description].
-- If the content is in the form of "anything" (LIKE '"%"')
-- Then take the whole text without the first and last characters
-- (from the 2nd character and the LEN([Description]) - 2th character)
UPDATE [Messages]
SET [Description] = SUBSTRING([Description], 2, LEN([Description]) - 2)
WHERE [Description] LIKE '"%"'
You can use following query which worked for me-
For updating-
UPDATE table SET colName= REPLACE(LTRIM(RTRIM(REPLACE(colName, '"', ''))), '', '"') WHERE...
For selecting-
SELECT REPLACE(LTRIM(RTRIM(REPLACE(colName, '"', ''))), '', '"') FROM TableName
you could replace the quotes with an empty string...
SELECT AllRemoved = REPLACE(CAST(MyColumn AS varchar(max)), '"', ''),
LeadingAndTrailingRemoved = CASE
WHEN MyTest like '"%"' THEN SUBSTRING(Mytest, 2, LEN(CAST(MyTest AS nvarchar(max)))-2)
ELSE MyTest
END
FROM MyTable
Some UDFs for re-usability.
Left Trimming by character (any number)
CREATE FUNCTION [dbo].[LTRIMCHAR] (#Input NVARCHAR(max), #TrimChar CHAR(1) = ',')
RETURNS NVARCHAR(max)
AS
BEGIN
RETURN REPLACE(REPLACE(LTRIM(REPLACE(REPLACE(#Input,' ','¦'), #TrimChar, ' ')), ' ', #TrimChar),'¦',' ')
END
Right Trimming by character (any number)
CREATE FUNCTION [dbo].[RTRIMCHAR] (#Input NVARCHAR(max), #TrimChar CHAR(1) = ',')
RETURNS NVARCHAR(max)
AS
BEGIN
RETURN REPLACE(REPLACE(RTRIM(REPLACE(REPLACE(#Input,' ','¦'), #TrimChar, ' ')), ' ', #TrimChar),'¦',' ')
END
Note the dummy character '¦' (Alt+0166) cannot be present in the data (you may wish to test your input string, first, if unsure or use a different character).
To remove both quotes you could do this
SUBSTRING(fieldName, 2, lEN(fieldName) - 2)
you can either assign or project the resulting value
You can use TRIM('"' FROM '"this "is" a test"') which returns: this "is" a test
CREATE FUNCTION dbo.TRIM(#String VARCHAR(MAX), #Char varchar(5))
RETURNS VARCHAR(MAX)
BEGIN
RETURN SUBSTRING(#String,PATINDEX('%[^' + #Char + ' ]%',#String)
,(DATALENGTH(#String)+2 - (PATINDEX('%[^' + #Char + ' ]%'
,REVERSE(#String)) + PATINDEX('%[^' + #Char + ' ]%',#String)
)))
END
GO
Select dbo.TRIM('"this is a test message"','"')
Reference : http://raresql.com/2013/05/20/sql-server-trim-how-to-remove-leading-and-trailing-charactersspaces-from-string/
I use this:
UPDATE DataImport
SET PRIO =
CASE WHEN LEN(PRIO) < 2
THEN
(CASE PRIO WHEN '""' THEN '' ELSE PRIO END)
ELSE REPLACE(PRIO, '"' + SUBSTRING(PRIO, 2, LEN(PRIO) - 2) + '"',
SUBSTRING(PRIO, 2, LEN(PRIO) - 2))
END
Try this:
SELECT left(right(cast(SampleText as nVarchar),LEN(cast(sampleText as nVarchar))-1),LEN(cast(sampleText as nVarchar))-2)
FROM TableName

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