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;
Related
I have a problem with a cursor inside SQL Server stored procedure.
Here is the code:
if (#pEvento = 84)
begin
set #pAsun_mail = #pAsun_mail + ' FUP ' + CONVERT(varchar(10), #pFupID) + ' ' + #pVersion;
DECLARE #ConsecutivoTemp int, #FechaTemp date, #ValorTemp money, #CondicionTemp varchar(50), #GeneraBoletoTemp bit;
DECLARE CondicionPago_Cursor CURSOR FOR
SELECT fccp_Consecutivo, Fecha, Valor, Condicion, fccp_BoletosBancarios FROM [dbo].[fup_CuotasCondicionesPago]
WHERE fccp_entrada_cot_id = (SELECT [eect_id]
FROM fup_enc_entrada_cotizacion
WHERE [eect_fup_id] = #pFupID
AND [eect_vercot_id] = #pVersion) AND fccp_TipoPago_id = 3;
OPEN CondicionPago_Cursor;
FETCH NEXT FROM CondicionPago_Cursor INTO
#ConsecutivoTemp, #FechaTemp, #ValorTemp, #CondicionTemp, #GeneraBoletoTemp;
DECLARE #HTMLTableLeasing varchar(max);
WHILE ##FETCH_STATUS = 0
BEGIN
SET #HTMLTableLeasing = #HTMLTableLeasing + '<tr>';
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td>'+ CONVERT(varchar(3), #ConsecutivoTemp) +'</td>';
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td>'+ CONVERT(varchar(20), #FechaTemp) +'</td>';
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td>'+ CONVERT(varchar(15), #ValorTemp) +'</td>';
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td>'+ #CondicionTemp +'</td>';
IF #GeneraBoletoTemp = 1
BEGIN
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td><input type="checkbox" disabled checked /></td>';
END
ELSE
BEGIN
SET #HTMLTableLeasing = #HTMLTableLeasing + '<td><input type="checkbox" disabled/></td>';
END
SET #HTMLTableLeasing = #HTMLTableLeasing + '</tr>';
FETCH NEXT FROM CondicionPago_Cursor INTO
#ConsecutivoTemp, #FechaTemp, #ValorTemp, #CondicionTemp, #GeneraBoletoTemp;
END
CLOSE CondicionPago_Cursor
DEALLOCATE CondicionPago_Cursor
set #pMsg = #pMsg + #HTMLTableLeasing
end
And the error says:
Already exists a cursor with name 'CondicionPago_Cursor'
I tried checking again the order or STATEMENTS OPEN, FETCH, CLOSE, DEALLOCATE but I think they have a correct order.
I'm tryin to iterate over a set or records to create dynamically a body of a table, you can see the tags <th> and <td>.
As #Lamu already mentioned, there are better ways to compose (X)HTML.
Also, there is no need to concatenate strings like in the #JohnInk answer.
Here is a conceptual example for you, including CSS for styling.
It will work starting from SQL Server 2005 onwards.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (
ID INT IDENTITY PRIMARY KEY
, state CHAR(2)
, city VARCHAR(30)
);
INSERT INTO #tbl (state, city)
VALUES
('FL', 'Miami')
, ('CA', 'Los Angeles')
, ('TX', 'Austin');
-- DDL and sample data population, end
DECLARE #xhtmlBody XML
, #body NVARCHAR(MAX)
, #tableCaption VARCHAR(30) = 'US states and cities';
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;} ]]>
td:nth-child(3) <![CDATA[ {background-color: red;} ]]>
#green <![CDATA[ {background-color: lightgreen;} ]]>
</style>
</head>
<body>
<table border="1">
<caption><h2>{sql:variable("#tableCaption")}</h2></caption>
<thead>
<tr>
<th>No.</th>
<th>State</th>
<th>City</th>
</tr>
</thead>
<tbody>
{
for $row in /root/row
return <tr>
<td>{data($row/ID)}</td>
<td>{data($row/state)}</td>
<td>
{if ($row/city/text()="Los Angeles") then attribute id {"green"} else ()}
{data($row/city)}
</td>
</tr>
}
</tbody></table></body></html>'));
SELECT #xhtmlBody;
Output
Saved as a file, and tested in any Internet browser
First: the error comes from using the global cursor. So, every time you run this it will run into itself. Add a LOCAL keyword.
DECLARE CondicionPago_Cursor CURSOR LOCAL FOR
But, you want to avoid cursor loops whenever possible. They are much less efficient. You might do something like instead.
SELECT #HTMLTableLeasing = #HTMLTableLeasing + '<tr><td>' + CAST(fccp_Consecutivo
AS varchar(3)) + '</td><td>' +
CAST(Fecha AS varchar(20)) + '</td><td>' +
CAST(Valor AS varchar(15)) + '</td><td>' +
Condicion + '</td><td>' +
CASE WHEN GeneraBoleto = 1
THEN '<input type="checkbox" disabled checked />'
ELSE '<input type="checkbox" disabled/>' END +
'</td></tr>'
FROM [dbo].[fup_CuotasCondicionesPago]
WHERE fccp_entrada_cot_id = (SELECT [eect_id]
FROM fup_enc_entrada_cotizacion
WHERE [eect_fup_id] = #pFupID
AND [eect_vercot_id] = #pVersion) AND fccp_TipoPago_id = 3
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
I am trying to search a two column table with a CustomerID and a ServID. The primary key is the combination of both. I want the query to search if the combination is there. If it is return something I can use in c# to cancel the input or if it is not found have it insert the record. This is as far as I have made it after hours of searching.
IF (SELECT * FROM Cus_Ser WHERE customerID=inputnumber AND ServID=inputnumber) IS NULL
PRINT 'Already Exists'
ELSE
INSERT INTO Cus_Ser(CustomerID,ServID) VALUES(inputnumber, inputnumber)
Here is the code
#using WebMatrix.Data
#{
var CustomerID = Request.QueryString["CustomerID"];
var ServID = 0;
var db = Database.Open("Azure");
var selectedData = db.Query("SELECT * FROM Customer INNER JOIN Cus_Ser ON Customer.customerID=Cus_Ser.customerID INNER JOIN Service ON Cus_Ser.ServID=Service.ServID WHERE customer.CustomerID =" + CustomerID);
var grid = new WebGrid(source: selectedData);
var selectedData2 = db.Query("SELECT * FROM Service");
var grid2 = new WebGrid(source: selectedData2);
if (IsPost)
{ if (int.TryParse(Request.Form["ServID"], out int numbertest))
{
ServID = Int32.Parse(Request.Form["ServID"]);
var dbCommandSearch = "SELECT * FROM Cus_Ser WHERE customerID=" + CustomerID + " AND ServID=" + ServID;
//search = db.QuerySingle(dbCommandSearch);
//if ((CustomerID, "ServID") != search
db = Database.Open("Azure");
var insertCommand = "INSERT INTO cus_ser (customerID,ServID)VALUES(" + CustomerID + ", " + ServID + ")";
db.Execute(insertCommand);
Response.Redirect("~/ViewService?CustomerID=" + CustomerID);
}
//else
//{
//Validation.AddFormError("Entered Value is Not a Service Numberr");
//}
else
{
Validation.AddFormError("Entered Value is NOT a Service Number");
}
} }
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add Service</title>
<style>
.validation-summary-errors {
border: 2px dashed red;
color: red;
font-weight: bold;
margin: 12px;
}
</style>
</head>
<body>
<form method="post">
<fieldset>
<legend>Input Service To Add</legend>
<p>
<label for="ServID">Service ID:</label>
<input type="text" name="ServID" value="#ServID" />
</p>
<input type="hidden" name="CustomerID" value="#CustomerID" />
<p><input type="submit" name="buttonSubmit" value="Submit Changes" /></p>
</fieldset>
</form>
<p>Return to customer listing</p>
Multiple Inline SQL Statements
Your sample code seems to be very close. The QuerySingle method will return null if no matches are found. Thus you can check for a null value before issuing the insert statement, with something like:
ServID = Int32.Parse(Request.Form["ServID"]);
var dbCommandSearch = "SELECT * FROM Cus_Ser WHERE customerID=" + CustomerID + " AND ServID=" + ServID;
search = db.QuerySingle(dbCommandSearch);
if (search == null) { // record does not already exist
var insertCommand = "INSERT INTO cus_ser (customerID,ServID)VALUES(" + CustomerID + ", " + ServID + ")";
db.Execute(insertCommand);
Response.Redirect("~/ViewService?CustomerID=" + CustomerID);
}
else
{
Validation.AddFormError("Entered Value is Not a Service Numberr");
}
Single SQL Statement
You can combine this all into one big SQL statement, something like:
var sql = #"IF EXISTS (SELECT 1 FROM Cus_Ser WHERE customerID=#0 AND ServID=#1)
SELECT 0 as [Inserted];
ELSE
BEGIN
INSERT INTO Cus_Ser(CustomerID,ServID) VALUES(#0, #1)
SELECT 1 as [Inserted];
END";
You can execute this as a parameterized query, which is much safer* than the code you have:
var response = db.QuerySingle(sql, CustomerID, ServID); // passing the input value as a parameter
if (response.Inserted == 1) {
// WebMatrix might convert to a bool, in which you would want `response.Inserted == true` instead
Response.Redirect("~/ViewService?CustomerID=" + CustomerID);
}
else
{
Validation.AddFormError("Entered Value is Not a Service Numberr");
}
As I am not deeply familiar with WebMatrix, I am not 100% sure about this code. Hopefully it sets you in the right direction.
A word of warning: your original code is vulnerable to something called a SQL injection attack. Most programmers start out making that mistake; I know that I did. In summary: that inputnumber parameter could have a SQL statement in it instead of a number. If someone crafts that SQL Statement just right, then they could cause a lot of damage. For an entry-level programming assignment it is not something to worry about in detail. But as you progress in coding, you will need to learn how to use parameterized queries in order to guard against SQL injection. A few useful references:
SQL Injection
Introduction to Working with a Database in ASP.NET Web Pages (Razor) Sites
I am using Bootstrap 3 media objects and I have this code here dynamically I want to have 4 columns in one row,but the problem is that the last row will have spaces inbetween to the second row.
here is my code.
//content.php
for(var i=0;i<12;i++){
mymdedia+=
'<div class="media col-sm-3">'+
'<div class="media-left">'+
'<a href="#">'+
'<img src=".....">'+
'</a>'+
'</div>'+
'<div class="media-body">'+
'<h4 class="media-heading">'John Doe'</h4>'+
'<p>Live: '+data[i].address+'</p>'+
'</div>'+
'</div>';
}
$('#mycontainer').append(mymdedia);
//index.php
<div class="someclass">
<div class="row" id="mycontainer">
</div>
</div>
and this is the result looks like
I believe you are placing all the media objects in one row ... and they don't fit.
In every row that you've opened ( <div class='row'>...</div> ) you can place only 4 <div class='media col-sm-3'></div> ... because each col size = 3 ... ( 4x3 = 12 )
So in the for loop, after each 4 media objects - you should close the current row div and create a new <div class='row'> ...
See plunker: http://plnkr.co/edit/BJa3qdbKcYMDwhW809gp?p=preview
Right after the for loop:
for(var i=0;i<12;i++){
if ( i && i % 4 == 0 )
mymdedia += '</div><div class="row">'; // close row and create a new one
... your original code ...
}
mymdedia += '</div>' // close the last row outside the for loop ...
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