sql replace all characters between two strings - sql

I am trying to figure out a way to update / replace only text between two strings.
For instance I need to be able to update the field and replace only what's in between the following script tags leaving the text before the opening script tag untouched.
I want to keep this string<script type="text/javascript" language="javascript">********</script>
I suppose REPLACE is not going to work as the text in between the script tags will vary. Is there some type of wildcard?
UPDATE Products_Joined
SET TechSpecs = REPLACE (CAST(TechSpecs AS NVARCHAR(MAX)), '<script type="text/javascript" language="javascript">********</script>', '<script type="text/javascript" language="javascript">new text</script>' )
UPDATED: with #Parkyprg answer This works but doesn't replace the closing </script> tag.
I end up with this.
I want to keep this string new text</script>
How do we remove the closing script tag as well?
UPDATE Products_Joined
SET TechSpecs = REPLACE(CAST(TechSpecs AS NVARCHAR(MAX)),
SUBSTRING(CAST(TechSpecs AS NVARCHAR(MAX)),
CHARINDEX('<script type="text/javascript" language="javascript">',TechSpecs),
CHARINDEX('</script>',CAST(TechSpecs AS NVARCHAR(MAX))) -
CHARINDEX('<script type="text/javascript" language="javascript">',TechSpecs)
),' new text')

DECLARE #OpenTag varchar(100)
SET #OpenTag = '<script type="text/javascript" language="javascript">'
UPDATE Products_Joined
SET TechSpecs = STUFF(TechSpecs ,
CHARINDEX(#OpenTag, TechSpecs ,1) + LEN(#OpenTag),
CHARINDEX('</script>',TechSpecs ,1)-(CHARINDEX(#OpenTag, TechSpecs ,1) + LEN(#OpenTag)),
'New Text')

It may not be the best solution, but...
UPDATE Products_Joined
SET TechSpecs = REPLACE(TechSpecs,
SUBSTRING(TechSpecs,
CHARINDEX('<script type="text/javascript" language="javascript">',TechSpecs),
CHARINDEX('</script>',TechSpecs) -
CHARINDEX('<script type="text/javascript" language="javascript">',TechSpecs)
)
FROM MyTable

Related

Using "for xml" to format SQL results that include results that are NULL?

I have an SQL query basically as follows:
DECLARE #BODY1 NVARCHAR(MAX)
SET #BODY1 = CAST((SELECT td = Name + '</td><td>' + Number + '</td><td>' + Address + '</td>'
FROM
(
SELECT
Name, Number, Address
FROM
Table1
) as Sub
FOR XML PATH('tr'), type) AS VARCHAR(MAX))
SET #BODY1 = '<TABLE CELLPADDING="3" CELLSPACING="3" BORDER="1">'+
'<TR><TH>Name</TH><TH>Number</TH><TH>Address</TH></TR> +
+ REPLACE(REPLACE(#Body1, '<','<'), '>','>') + '</TABLE>'
EXEC MSDB.DBO.SP_SEND_DBMAIL
#PROFILE_NAME = 'NAME',
#RECEPIENTS = 'NAME#DOMAIN.COM',
#BODY = #Body1,
#SUBJECT = 'Details',
#BODY_FORMAT = 'HTML',
#EXECUTE_QUERY_DATABASE = 'NAME';
The data I have can be summarised as follows:
NAME NUMBER ADDRESS
Bob 12345 1 Street, Town
John 23456
Scott 34567 3 Avenue, City
When I run this code which sends me an email containing the results of the query, I only get Bob and Scott's record. This example is simplified, but if there are any rows that do not have data in each field then they do not show in the email.
I've read somewhere that perhaps this is due to needing another variable as part of the XML code, but I can't quite put my finger on what it is. Please can someone assist me?
Thanks in advance.
Your primary issue is that + will return null if any of the values are null. So you could use either ISNULL or CONCAT
But this is in any case not the correct way to create XML. You should just unpivot the values and use FOR XML properly.
DECLARE #BODY1 NVARCHAR(MAX) =
(
SELECT
ISNULL(v.td, '') AS td
FROM
Table1
CROSS APPLY (VALUES
(Name),
(Number),
(Address)
) v(td)
FOR XML PATH('tr')
);
You need to be able to prepare for the entire output of this expression to be NULL:
SET #BODY1 = CAST((SELECT td = Name + '</td><td>'
+ Number + '</td><td>'
+ Address + '</td>' ...
A couple of ways to handle that. You can use COALESCE to convert NULL to empty string:
SET #BODY1 = CAST((SELECT td = COALESCE(Name, '') + '</td><td>'
+ COALESCE(Number, '') + '</td><td>'
+ COALESCE(Address, '') + '</td>' ...
Or CONCAT(), which does that for you:
SET #BODY1 = CAST((SELECT td = CONCAT
(Name, '</td><td>', Number, '</td><td>', Address, '</td>') ...
There are also certainly other approaches to your entire problem space that are a lot less messy, but this is at least a start to get your missing row back.
For example, on SQL Server 2017, you can use STRING_AGG() and CONCAT_WS():
SELECT #BODY1 = '<table ...>
<TR><TH>Name</TH><TH>Number</TH><TH>Address</TH></TR><tr>'
+ STRING_AGG('<td>'+CONCAT_WS('</td><td>',Name,Number,Address)
+'</td>','</tr><tr>') + '</tr></table>'
FROM dbo.Table1;
This is also, admittedly, ugly. Another way:
SELECT #BODY1 = '<table ...>
<TR><TH>Name</TH><TH>Number</TH><TH>Address</TH></TR>
<tr>' + td + '</table>'
FROM
(
SELECT td FROM
(
SELECT Name = COALESCE(Name, ''),
Number = COALESCE(Number,''),
Address = COALESCE(Address,'')
FROM dbo.Table1
) AS cp UNPIVOT(td FOR cols IN (Name, Number, Address)) AS up
FOR XML PATH('tr')
) AS x(td);
Please try the following XQuery based approach that gererates XHTML for the email.
Notable points:
No strings concatenation.
No worries for NULL values.
Very easy to create, very easy to maintain.
UI styling is controlled via CSS.
SQL
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, [Name] VARCHAR(20), Number CHAR(5), [Address] VARCHAR(100));
INSERT INTO #tbl (Name, Number, Address) VALUES
('Bob ', '12345' ,'1 Street, Town'),
('John ', '23456' , NULL),
('Scott', '34567' ,'3 Avenue, City');
DECLARE #xhtmlBody XML
, #body NVARCHAR(MAX)
, #tableCaption VARCHAR(30) = 'Customers list';
SET #xhtmlBody = (SELECT (
SELECT * FROM #tbl FOR XML PATH('row'), TYPE, ROOT('root'))
.query('<html><head>
<meta charset="utf-8"/>
(: including embedded CSS styling :)
<style>
table <![CDATA[ {border-collapse: collapse; width: 300px;} ]]>
th <![CDATA[ {background-color: #4CAF50; color: white;} ]]>
th, td <![CDATA[ { text-align: left; padding: 8px;} ]]>
tr:nth-child(even) <![CDATA[ {background-color: #f2f2f2;} ]]>
#green <![CDATA[ {background-color: lightgreen;} ]]>
</style>
</head>
<body>
<table border="1">
<caption><h2>{sql:variable("#tableCaption")}</h2></caption>
<thead>
<tr>
<th>No.</th>
<th>Name</th>
<th>Number</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{
for $row in /root/row
return <tr>
<td>{data($row/ID)}</td>
<td>{data($row/Name)}</td>
<td>{data($row/Number)}</td>
<td>{data($row/Address)}</td>
</tr>
}
</tbody></table></body></html>'));
SELECT #xhtmlBody;
SET #body = CAST(#xhtmlBody AS NVARCHAR(MAX));
Output

Remove html tags from a column

I have the a column in my table which stores a paragraph like below :
<p>I like it.</p>this is my job.<main>current.</main>
I want to remove the tags <p>, </p>, and and all tags between < and >.
So my expected output will be like below :
I like it. this is my job. current.
please try this
DECLARE #txt NVARCHAR(MAX) = '<p>I like it.</p>this is my job.<main>current.</main>'
SELECT x.value('.', 'NVARCHAR(MAX)') FROM ( SELECT x =
CAST(REPLACE(REPLACE(#txt, '>', '/>'), '</', '<') AS XML) ) r
this will help to remove all tags
UPDATE: Samir's answer is better than mine as it can deal with html-crap
(as long as there is no < or > as normal content :-)
You can try this:
If your string is valid XML (meaning XHTML) you might go this route:
DECLARE #yourString NVARCHAR(100)=N'<p>I like it.</p>this is my job.<main>current.</main>';
SELECT CAST(#yourString AS XML).value('.','nvarchar(max)');
returns
I like it.this is my job.current.
Using . as the XPath will return the whole content as is...
Any invalid XML (very likely with simple html) will break this...
You can use giant REPLACE() :
SELECT REPLACE(REPLACE(REPLACE(REPLACE(col, '<p>', ''), '</p>', ''), '<main>, ''), '</main>', '')
If you are working the latest SQL version then this will be easy to write using TRANSLATE() :
SELECT TRANSLATE(col, '<p></p><main></main>', '')
If u want remove tags when select, you can do a normal SELECT and clear string:
SELECT column FROM my_table;
$value = $row["column"];
$value_replaced = str_replace('<p>', '', $value);
$value = $value_replaced;
$value_replaced = str_replace('</p>', '', $value);
$value = $value_replaced;
$value_replaced = str_replace('<main>', '', $value);
$value = $value_replaced;
$value_replaced = str_replace('</main>', '', $value);

Delete script form xml document in SQL Server

I want to delete content from xml or txt document in SQL Server 2014 for this example:
<div class="infotagtitle">
<script type="text/javascript">
var sc_project=9934926;
var sc_invisible=1;
var sc_security="00dd8003";
var scJsHost = (("https:" == document.location.protocol) ?
"https://secure." : "http://www.");
document.write("<sc"+"ript type='text/javascript' src='" +
scJsHost+
"statcounter.com/counter/counter.js'></"+"script>");
</script>
</div>
Output:
<div class="infotagtitle">
</div>
The text code from the question is clearly HTML and not well-formed XML.
As such, the text can't be simply casted or converted to the XML type.
Which means XML type functions like f.e. SET #myXML.modify('delete //script'); aren't an option.
This example code uses a table variable to demonstrate updating a table with an NVARCHAR that contains HTML with script tags.
It uses PATINDEX to find the script code in the HTML.
An update is looped till no records remain with a script tag in the html.
declare #T table (Id int identity(1,1), html_text nvarchar(max));
insert into #T (html_text) values
(N'<html>
<body>
<div class="infotagtitle">
<script type="text/javascript">
var sc_project=9934926;
var sc_invisible=1;
var sc_security="00dd8003";
var scJsHost = (("https:" == document.location.protocol) ?
"https://secure." : "http://www.");
document.write("<sc"+"ript type=''text/javascript'' src=''" +
scJsHost+
"statcounter.com/counter/counter.js''></"+"script>");
</script>
</div>
<div class="othertagtitle">
<script type="text/javascript">
document.write("<script type=''text/javascript'' src=''" +
otherHost+
"othercounter.com/counter/counter.js''></"+"script>");
</script>
</div>
</body>
<html>');
declare #N INT, #Counter INT = 0;
select #N = count(*) from #T where patindex('%<script %',html_text) > 0;
while (#N > 0 AND #Counter < 10)
begin
set #Counter = #Counter + 1; -- just a safety measure to avoid an infinite loop
update #T
set html_text = concat(substring(html_text,1,patindex('%<script %',html_text)-1),substring(html_text,patindex('%</script>%',html_text)+9,len(html_text)))
where patindex('%<script %',html_text) > 0;
select #N = count(*) from #T where patindex('%<script %',html_text) > 0;
end;
select * from #T;

how to bypass the 65535 character limit in a select statement using "FOR XML"

I am aware of the 65535 truncation for text datatypes (and Varchar(MAX) as well). I am also aware of XML outputs that can be set to unlimited. I have a table that stores XML strings in a varchar(MAX) column called GEOM.
My problem is that the xml snippet held in the geom column can exceed 65535 characters. I figure since it's XML, and I'm creating an XML output in my code anyways, why not just build the xml and send that out as such, since I can set XML output to "Unlimited".
USE [buyerhero]
GO
/****** Object: StoredProcedure [dbo].[GEOIDKMLCOUNTY] Script Date: 9/17/2015 11:18:55 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GEOIDKMLCOUNTY] #CountyID nvarchar(30)
AS
DECLARE #kml XML
DECLARE #kmlout NVARCHAR(MAX)
SELECT #kml = CAST('<?xml version="1.0" encoding="utf-16" ?>' +
'<kml xmlns="http://www.opengis.net/kml/2.2">' +
'<Document>' +
' <Style id="Licensed">
<LineStyle>
<color>ff000000</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<color>1e1400FF</color>
<fill>1</fill>
<outline>1</outline>
</PolyStyle>
</Style>
<Style id="NotLicensed">
<LineStyle>
<color>ff000000</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<color>1e14F0FF</color>
<fill>1</fill>
<outline>1</outline>
</PolyStyle>
</Style>
<Style id="Other">
<LineStyle>
<color>ff000000</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<color>1e007800</color>
<fill>1</fill>
<outline>1</outline>
</PolyStyle>
</Style>' +
(
select
'<![CDATA[{"County":"' + r.CountyName + ', ' + r.State + '", "GEOID": "'+t.GEOID+'"}]]>' as Name,
case t.IsLicensed
when 2 then '#Licensed'
when 1 then '#NotLicensed'
else '#Other'
end as StyleURL,
cast(replace(geom,'"','') as xml) as Geometry
from Tracts t
join census_county_ref c on t.GEOID = c.GEOID
join FIPSCountyCode r on c.STATEFP = r.StateANSI and c.COUNTYFP = r.CountyANSI
where r.CountyID = #CountyID
FOR XML PATH(''), ELEMENTS) + '</Document></kml>' AS XML)
--
-- Perform replacement of < and > with < and > respectively
--
SET #kmlout = REPLACE(REPLACE(CAST(#kml AS NVARCHAR(MAX)), '<', '<'), '>', '>')
SET #kmlout = REPLACE(#kmlout, 'utf-16', 'utf-8')
--
-- Return kmlout
--
SELECT #kmlout
in spite of the idea the geom columns is xml and I'm using cast(replace(geom,'"','') as xml) which is varchar(max), that field still gets truncated.
How do I "untruncate" the field so I can output the XML?
Thanks.
Use the concat function instead the + operator. the plus operator is limited to 8000 bytes.
SELECT #kml =CAST(concat('your xml', the select,'the other xml')

Regarding computed values in extjs

Consider the following piece of code :
<script type="text/javascript" src="/<Computed Value>/samples/home.js"></script>
In the above example, how does 'Computed Value' get populated. I mean what is the general way of doing it in extjs?.
Thanks in advance.
Take a look at the Ext.String.format function: http://docs-origin.sencha.com/extjs/4.1.3/#!/api/Ext.String-method-format. It should do what you need:
var cls = 'my-class',
text = 'Some text';
var s = Ext.String.format('<div class="{0}">{1}</div>', cls, text);
// s now contains the string: '<div class="my-class">Some text</div>'