Update, find/replace for xml field - sql

I have a Page table in my database.
Lets say for simplicity it has two columns; title and xmlData
It has Title something like "my example "
and I have a xml field that looks like:
<MA>
<A>
<URL>my-example-</URL>
<id>5</id>
</A>
</MA>
I am trying to do a find replace of any url that has "-" at the end, and remove the only the last trailing "-" if it exists
and remove the trailing space(if it has one, to title)
I am able to grab the rows that need to be changed by doing
select * from Pages
where title like '% '
(there is some joins and stuff, but that is basically it)

This will replace one occurrence of the URL for each row. By the look of your sample XML you have only one URL per row.
with C1 as
(
select xmlData,
xmlData.value('(/MA/A/URL/text())[1]', 'nvarchar(500)') as URL
from Pages
),
C2 as
(
select xmlData,
URL,
left(URL, len(URL) - 1) as URL2
from C1
where right(URL, 1) = '-'
)
update C2
set xmlData.modify('replace value of (/MA/A/URL/text())[1]
with sql:column("C2.URL2")')
Extract the URL value in CTE C1.
Remove the last '-' from the URL and put that in URL2 in CTE C2. Also remove the rows that does not need to be updated.
Update the XML using modify() Method (xml Data Type)
And here is another version that does the job in the XML part of the query instead.
update Pages
set xmlData.modify('replace value of (/MA/A/URL/text())[1]
with fn:substring((/MA/A/URL/text())[1], 1, fn:string-length((/MA/A/URL/text())[1])-1)')
where xmlData.exist('/MA/A/URL[fn:substring(text()[1], fn:string-length(text()[1]), 1) = "-"]') = 1
It is only possible to update one node at a time so if you have multiple URL's in in one row you have to put the code above in a loop and do the updates as long as there is something to update. You could use ##ROWCOUNT to check if the update did update anything and redo the update until ##ROWCOUNT = 0.

you can use CHARINDEX function to check if exists a character '-' and so on you can use SUBSTIRNG function to grab only part to replace of your text.
Example:
declare #a varchar(100)
set #a = 'HI, TODAY IS A - BEAUTIFUL DAY'
select
case
when charindex('-',#a) >= 0 then
substring(#a, 0, charindex('-',#a)-1) +
substring(#a, charindex('-', #a) + 1, 100)
else #a
end

Related

I want to update a string in a table

I have a table, content_history with a column, doc_filename, and each row has a string value. Each string has a | and the portion in front of the | is a filepath. I want to replace that portion of the string with the correct filepath if it doesn't already match. What is the best way to go about doing this? Currently I use:
UPDATE content_history
SET doc_filename = replace (doc_filename, 'path that needs to be replaced', 'new path')
WHERE doc_filename LIKE 'old path%'
But if I don't have the exact path it doesn't replace so I have to run a select * query and manually go through and input all the different paths that are incorrect. It's not a viable long-term solution
Ideally you wouldn't store multiple values as delimited values in a single value, you should have a separate column for each distinct value, then you wouldn't be asking such a question.
You can use stuff:
set doc_filename=Stuff(doc_filename, 1, CharIndex('|', doc_filename)-1, 'new path')
you need to split value to avoid an incorrect update
update CH
set CH.doc_filename = 'new_path' + '|' + P.right_part
from content_history CH
outer apply
(
select left(CH.doc_filename, charindex('|', CH.doc_filename) - 1) as left_part
,right(CH.doc_filename, len(CH.doc_filename) - charindex('|', CH.doc_filename)) as right_part
where charindex('|', CH.doc_filename) != 0
) P
where P.left_part = 'old_path'

Replace Function - Handling single quotes and forward slashes in SQL SERVER 2008

I want to replace some data from my database where single quotes and slashes are present.
The line below is exactly how it appears in the database and I only want to remove 'F/D', from the record.
('P/P','F/D','DFC','DTP')
Been using varations of
UPDATE tablename SET columnname = REPLACE(columnname, '''F/D,''', '')
WHERE RECORDID = XXXXX
Also been using varations of
UPDATE tablename SET columnname = REPLACE(columnname, 'F/D,', '')
WHERE RECORDID = XXXXX
Seems like it should be a simple fix but I haven't had any luck yet - all suggestions are appreciated.
The reason your's doesn't work is because you aren't including the quotes. You are looking for F/D, and 'F/D,' and your data it is 'F/D',.
If it's simply 'F/D' from all values you want removed, then you also need to remove a comma and the quotes. This method removes 'F/D' and then, any double commas (in case 'F/D' is in the middle of the string).
declare #var varchar(64) = '(''P/P'',''F/D'',''DFC'',''DTP'')'
select replace(replace(#var,'''F/D''',''),',,',',')
--update tablename
--set columnname = replace(replace(columnname,'''F/D''',''),',,',',')
--where RECORDID = 1324
If you want to replace the second element in the string, here is a way:
select
#var
--find the location of the first comma
,charindex(',',#var,0)
--find the location of the second comma
,charindex(',',#var,charindex(',',#var) + 1)
--Put it all together, using STUFF to replace the values between this range with nothing
,stuff(#var,charindex(',',#var,0),charindex(',',#var,charindex(',',#var) + 1) - charindex(',',#var,0),'')
Your first version should work fine if the comma is in the right place:
UPDATE tablename
SET columnname = REPLACE(columnname, '''F/D'',', '')
WHERE RECORDID = XXXXX;
Note that this will not replace 'F/D' if it is the first or last element in the value. If that is an issue, I would suggest that you ask another question.

Needing to parse out data

I am trying to parse out certain data from a string and I am having issues.
Here is the string:
1=BETA.1.0^2=175^3=812^4=R^5=N^9=1^12=1^13=00032^14=REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR.^10=107~117~265~1114~3143~3505~3506~3513~5717^11=SA16~1~WY~WY~A~S~20100210~001~SE62^-omitted due to existing Rep Not Found
I need to return this "REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR."
Here is my query SELECT CONVERT(VARCHAR(5000),CHARINDEX('14=',Column))FROM Table
If you're parsing, can we assume that you don't know what might come after the '^14=', but you need to capture whatever does? So searching for a particular string won't work because anything could come after '^14='. The best approach is to identify the longest reliable specific string that gives you a "foothold" to find the data you're looking for. What you don't want to do is accidentally capture the wrong data if the '^14=' appears more than once in your string. It looks like the '^' is your delimiter, since I don't see one at the start of the string. So you were actually on the right track, you just need to use SUBSTRING as a commenter mentioned. You also need to identify a marker for the end of the error message, which looks like it might be the next occurring '^', correct? Check several samples to be sure of this, and make sure the end marker doesn't at any point exist before your start marker or you'll get an error.
SELECT CAST((SUBSTRING(Column,CHARINDEX('14=',Column,0),CHARINDEX('^',Column,CHARINDEX('14=',Column,0) + 1) - CHARINDEX('14=',Column,0))) AS VARCHAR(5000)) FROM Table
You may need to increment or decrement the start position and end position by doing a +1 or -1 to fully capture your error message. But this should dynamically grab any length error message provided you are positive of your starting and ending markers.
I also have here a table-valued parsing function, where you would pass it the string and the '^' and it will return a table of data with not only the 14=, but everything.
CREATE function [dbo].[fn_SplitStringByDelimeter]
(
#list nvarchar(8000)
,#splitOn char(1)
)
returns #rtnTable table
(
id int identity(1,1)
,value nvarchar(100)
)
as
begin
declare #index int
declare #string nvarchar(4000)
select #index = 1
if len(#list) < 1 or #list is null return
--
while #index!= 0
begin
set #index = charindex(#splitOn,#list)
if #index!=0
set #string = left(#list,#index - 1)
else
set #string = #list
if(len(#string)>0)
insert into #rtnTable(value) values(#string)
--
set #list = right(#list,len(#list) - #index)
if len(#list) = 0 break
end
return
end
It sounds like you're trying to get the value of argument 14. This should do it:
select substring(
someData
, charindex('^14=',someData) + 4
, charindex('^',someData, charindex('^14=',someData) + 4) - charindex('^14=',someData) - 4
) errorMessage
from myData
where charindex('^14=',someData) > 0
and charindex('^',someData, charindex('^14=',someData) + 4) > 0
Try it here: http://sqlfiddle.com/#!18/22f23/2
This gets a substring of the given input.
The substring starts at the first character after the string ^14=; i.e. we get the index of ^14= in the string, then add 4 to it to skip over the matched characters themselves.
The substring ends at the first ^ character after the one in ^14=. We get the index of that character, then subtract the starting position from it to get the length of the desired output.
Caveats: If there is no parameter (^) after ^14= this will not work. Equally if there is no ^14= (even if the string starts 14=) this will not work. From the information available that's OK; but if this is a concern please say and we can provide something to handle that more complex scenario.
Code to create table & populate demo data
create table myData (someData nvarchar(256))
insert myData (someData)
values ('1=BETA.1.0^2=175^3=812^4=R^5=N^9=1^12=1^13=00032^14=REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR.^10=107~117~265~1114~3143~3505~3506~3513~5717^11=SA16~1~WY~WY~A~S~20100210~001~SE62^-omitted due to existing Rep Not Found')
, ('1xx^14=something else.^10=xx')
You could try to use a Case When statement with wildcards to find the value that you want.
Example:
SELECT
CASE
WHEN x LIKE '%REP Not Found%'
THEN 'REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR'
ELSE
''
END AS x
FROM
#T1
You could use this query (assuming MySQL database):
-- item is the column that contains the string
select SUBSTR(item, LOCATE('REP',item), LOCATE('REPRGR.',item) + LENGTH('REPRGR.') - LOCATE('REP', item)) info_msg from Table;
Illustration:
create table parsetest (item varchar(5000));
insert into parsetest values('1=BETA.1.0^2=175^3=812^4=R^5=N^9=1^12=1^13=00032^14=REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR.^10=107~117~265~1114~3143~3505~3506~3513~5717^11=SA16~1~WY~WY~A~S~20100210~001~SE62^-omitted due to existing Rep Not Found');
select * from parsetest;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| item |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1=BETA.1.0^2=175^3=812^4=R^5=N^9=1^12=1^13=00032^14=REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR.^10=107~117~265~1114~3143~3505~3506~3513~5717^11=SA16~1~WY~WY~A~S~20100210~001~SE62^-omitted due to existing Rep Not Found |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
select SUBSTR(item, LOCATE('REP',item), LOCATE('REPRGR.',item) + LENGTH('REPRGR.') - LOCATE('REP', item)) info_msg from parsetest;
+------------------------------------------------------+
| info_msg |
+------------------------------------------------------+
| REP NOT FOUND ON REP TABLE, CANNOT INSERT TO REPRGR. |
+------------------------------------------------------+

How to i replace contents of one column with only part of another column in the same table?

I have columnA with /home/docs/test1 . I want the other column (columnB) to only be populated with only test1. I want to do this for the whole table.
You could use a reverse trick here:
UPDATE yourTable
SET columnB = REVERSE(SUBSTRING(REVERSE(columnA),
1, CHARINDEX('/', REVERSE(columnA)) - 1));
If some of the paths might be only a single level, i.e. there is no path divider / present, and in that case you would want to retain the entire path, then you can slightly modify the above to the following:
UPDATE yourTable
SET columnB = CASE WHEN CHARINDEX('/', columnA) > 0
THEN REVERSE(SUBSTRING(REVERSE(columnA),
1, CHARINDEX('/', REVERSE(columnA)) - 1))
ELSE columnA END;
Here is a demo showing that the above logic works:
Demo
If you need last tuple then above is fine. But if need Random then below query will help to make it split.
DECLARE #Var_xml XML
SELECT #Var_xml = Cast('<root><x>'+ Replace('/home/docs/test1', '/', '</x><x>')+ '</x></root>' AS XML)
SELECT DISTINCT f.x.value('.', 'VARCHAR(100)') AS tupple
FROM #Var_xml.nodes('/root/x') f(x)

Extract e-mail address from string

I have table called Entities with the column CustomData.
I need to extract the email address from each row.
Also if value is null I need to to show as null.
Sample rows from CustomData:
Id CustomData Name
273 [{"Name":"Customer","Value":"test customer"},{"Name":"Address","Value":null},{"Name":"Email","Value":null},{"Name":"Company Name","Value":null},{"Name":"Other Phone","Value":null}] 2323123213
274 [{"Name":"Customer","Value":"Cash Sale"},{"Name":"Address","Value":null},{"Name":"Email","Value":"test#outlook.com"},{"Name":"Company Name","Value":null},{"Name":"Other Phone","Value":null}] 2222222222
This is the string i will be using to update my system.
I have previously achieved selecting the phone number form this same data but it was a fixed length. I can't seem to pull the e-mail address.
I will post a couple of the different methods I have tried so far once im back at my PC
Well, in such a denormalized data your only option is to parse it and try to get email. Most elegant way - is to use json parser, but it is not awailable in current versions of sql server, so you have to parse it manually.
Assuming each record for email starts with {"Name":"Email","Value":, you can do it in a few steps:
Find position of {"Name":"Email","Value": in your string.
Find first occurence of } in the right remainder of the string.
Get substring in between.
Check if it is string equals to 'null' - then return null, otherwise return string itself.
So it can be done like in this snippet:
declare #data nvarchar(max), #pattern nvarchar(max)
select #data = '[{"Name":"Customer","Value":"test customer"},
{"Name":"Address","Value":null},
{"Name":"Email","Value":null},
{"Name":"Company Name","Value":null},
{"Name":"Other Phone","Value":null}]'
select #pattern = '{"Name":"Email","Value":'
select nullif(substring(#data,
charindex(#pattern, #data, 0) + len(#pattern),
charindex('}', #data, charindex(#pattern, #data, 0))
- charindex(#pattern, #data, 0) - len(#pattern)
), 'null')