How to convert a T-SQL query into a Stored Procedure? - sql

I am running SQL Server 2012 and I need to convert a T-SQL query into a Stored Procedure. My aim is to run a SQL job that will execute this Stored Procedure on a daily basis.
My T-SQL query stands as follows:
DECLARE #Body NVARCHAR(MAX),
#TableHead VARCHAR(1000),
#TableTail VARCHAR(1000)
SET #TableTail = '</table></body></html>' ;
SET #TableHead = '<html><head>' + '<style>'
+ 'td {border: solid black;border-width: 1px;padding-left:5px;padding-right:5px;padding-top:1px;padding-bottom:1px;font: 11px arial} '
+ '</style>' + '</head>' + '<body>' + 'Report generated on : '
+ CONVERT(VARCHAR(50), GETDATE(), 106)
+ ' <br> <table cellpadding=0 cellspacing=0 border=0>'
+ '<tr> <td bgcolor=#E6E6FA><b>StayYear</b></td>'
+ '<td bgcolor=#E6E6FA><b>Market</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jan</b></td>'
+ '<td bgcolor=#E6E6FA><b>Feb</b></td>'
+ '<td bgcolor=#E6E6FA><b>Mar</b></td>'
+ '<td bgcolor=#E6E6FA><b>Apr</b></td>'
+ '<td bgcolor=#E6E6FA><b>May</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jun</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jul</b></td>'
+ '<td bgcolor=#E6E6FA><b>Aug</b></td>'
+ '<td bgcolor=#E6E6FA><b>Sep</b></td>'
+ '<td bgcolor=#E6E6FA><b>Oct</b></td>'
+ '<td bgcolor=#E6E6FA><b>Nov</b></td>'
+ '<td bgcolor=#E6E6FA><b>Dec</b></td>';
SET #Body = ( SELECT *
FROM View1
FOR XML RAW('tr'),
ELEMENTS
)
SELECT #Body = #TableHead + ISNULL(#Body, '') + #TableTail
What are the steps to convert the above into a Stored Procedure?

You Can add make your script as a Stored Procedure by simply binding your Query inside a Create Procedure statement. Like this
CREATE PROCEDURE <Database Schema>.<Procedue Name>
AS
BEGIN
<Your Script>
END
you can copy and paste your Query between the BEGIN and END.
Like this
CREATE PROCEDURE dbo.sProc_MyProc
AS
BEGIN
DECLARE #Body NVARCHAR(MAX),
#TableHead VARCHAR(1000),
#TableTail VARCHAR(1000)
SET #TableTail = '</table></body></html>' ;
SET #TableHead = '<html><head>' + '<style>'
+ 'td {border: solid black;border-width: 1px;padding-left:5px;padding-right:5px;padding-top:1px;padding-bottom:1px;font: 11px arial} '
+ '</style>' + '</head>' + '<body>' + 'Report generated on : '
+ CONVERT(VARCHAR(50), GETDATE(), 106)
+ ' <br> <table cellpadding=0 cellspacing=0 border=0>'
+ '<tr> <td bgcolor=#E6E6FA><b>StayYear</b></td>'
+ '<td bgcolor=#E6E6FA><b>Market</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jan</b></td>'
+ '<td bgcolor=#E6E6FA><b>Feb</b></td>'
+ '<td bgcolor=#E6E6FA><b>Mar</b></td>'
+ '<td bgcolor=#E6E6FA><b>Apr</b></td>'
+ '<td bgcolor=#E6E6FA><b>May</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jun</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jul</b></td>'
+ '<td bgcolor=#E6E6FA><b>Aug</b></td>'
+ '<td bgcolor=#E6E6FA><b>Sep</b></td>'
+ '<td bgcolor=#E6E6FA><b>Oct</b></td>'
+ '<td bgcolor=#E6E6FA><b>Nov</b></td>'
+ '<td bgcolor=#E6E6FA><b>Dec</b></td>';
SET #Body = ( SELECT *
FROM View1
FOR XML RAW('tr'),
ELEMENTS
)
SELECT #Body = #TableHead + ISNULL(#Body, '') + #TableTail
END

Simply right-click 'Stored Procedures' and click 'Stored Procedure'.
A new window will open with some very basic code.
Delete the stuff in green
Name your Stored Procedure, with no spaces in the name of the SProc.
Paste your SQL script in between the BEGIN and END clauses.
Hit F5 to compile your Sproc.
If everything is setup correctly, you will get a message that reads
Command(s) completed successfully.

Related

SQL Cursor Problem CODE 16915 Cursor name already exists

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

Barcode CODE_128 using PrintHTML with Qz Tray

Good Day All,
Right now, i'm trying to print using HTML with Qz-Tray. Can i make a barcode on that template HTML. The Problem is, that HTML template is STRING so it can not be change it using Javascript and I'm Trying to use Libre Font 128 Font Family but still not working.
https://www.w3schools.com/howto/tryit.asp?font=Libre%20Barcode%20128 i want to use that library, in this
function printHTML() {
var config = getUpdatedConfig();
var colA = '<h2>* QZ Print Plugin HTML Printing *</h2>' +
'<span style="color: #F00;">Version:</span> ' + qzVersion + '<br/>' +
'<span style="color: #F00;">Visit:</span> https://qz.io/';
var colB = '<img src="' + getPath() + '/assets/img/image_sample.png">';
var printData = [
{
type: 'html',
format: 'plain',
data: '<html>' +
' <table style="font-family: monospace; border: 1px;">' +
' <tr style="height: 6cm;">' +
' <td valign="top">' + colA + '</td>' +
' <td valign="top">' + colB + '</td>' +
' </tr>' +
' </table>' +
'</html>'
}
];
qz.print(config, printData).catch(displayError);
}
or this https://barcode-coder.com/en/barcode-jquery-plugin-201.html

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

How to convert string which is output of select .....from for JSON AUTO to JSON Formatted file which is readable without using third party tool SSIS

HI I am writing SSIS package to get the output from
Select a,b,c from CUST FOR JSON AUTO
However I am getting output in a single row like
{"a":"Rock" ,"b":"paper" ,"c":"scissors"}, {"a":"Rock" ,"b":"paper" ,"c":"scissors"}, {"a":"Rock" ,"b":"paper" ,"c":"scissors"}....
However I want output as
{
"a":"Rock",
"b":"paper",
"c":"scissors"
},
{
"a":"Rock",
"b":"paper",
"c":"scissors"
},
{
"a":"Rock",
"b":"paper",
"c":"scissors"
},
My client argument is the Json file will be big file and he don't want to do extra formatting and should be readable
If you can add a javascript component to SSIS, it can be done.
(I'm not sure on how to do that in SSIS). But here is how you do it in javascript
I have a way to get this done rather messy way, but you can see whether that serves you the purpose
DECLARE #nl varchar(2) = char(13), #Json nvarchar(MAX) = (Select a,b,c from #CUST FOR JSON AUTO)
Select #Json = Replace(#Json, '[{','[' + #nl + '{' + #nl)
Select #Json = Replace(#Json, '{','{' + #nl)
Select #Json = Replace(#Json, '","','",' + #nl + '"' )
Select #Json = Replace(#Json, '"},{','"' + #nl + '},' + #nl + #nl + '{' )
Select #Json = Replace(#Json, '"}]','"' + #nl + '}' + #nl + ']' + #nl + #nl)
Select #Json as FormattedJSON
And here is the fiddle with more improvements

How to correct the scalar variable declaration error in my SQL job?

I am using SQL Server 2012 and I have the following stored procedure which is returning the required output in the form of a HTML table:
CREATE PROCEDURE dbo.ITB_SendEmail
AS
BEGIN
DECLARE #Body NVARCHAR(MAX),
#Body2 NVARCHAR(MAX),
#TableHead VARCHAR(1000),
#TableTail VARCHAR(1000)
SET #TableTail = '</table></body></html>' ;
SET #TableHead = '<html><head>' + '<style>'
+ 'td {border: solid black;border-width: 1px;padding-left:5px;padding-right:5px;padding-top:1px;padding-bottom:1px;font: 11px arial} '
+ '</style>' + '</head>' + '<body>' + 'Report generated on : '
+ CONVERT(VARCHAR(50), GETDATE(), 106)
+ ' <br> <table cellpadding=0 cellspacing=0 border=0>'
+ '<tr> <td bgcolor=#E6E6FA><b>StayYear</b></td>'
+ '<td bgcolor=#E6E6FA><b>Market</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jan</b></td>'
+ '<td bgcolor=#E6E6FA><b>Feb</b></td>'
+ '<td bgcolor=#E6E6FA><b>Mar</b></td>'
+ '<td bgcolor=#E6E6FA><b>Apr</b></td>'
+ '<td bgcolor=#E6E6FA><b>May</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jun</b></td>'
+ '<td bgcolor=#E6E6FA><b>Jul</b></td>'
+ '<td bgcolor=#E6E6FA><b>Aug</b></td>'
+ '<td bgcolor=#E6E6FA><b>Sep</b></td>'
+ '<td bgcolor=#E6E6FA><b>Oct</b></td>'
+ '<td bgcolor=#E6E6FA><b>Nov</b></td>'
+ '<td bgcolor=#E6E6FA><b>Dec</b></td>';
SET #Body = ( SELECT td = StayYear, '',
td = Market, '',
td = Jan, '',
td = Feb, '',
td = Mar, '',
td = Apr, '',
td = May, '',
td = Jun, '',
td = Jul, '',
td = Aug, '',
td = Sep, '',
td = Oct, '',
td = Nov, '',
td = Dec, ''
FROM View1
FOR XML RAW('tr'),
ELEMENTS
)
SET #Body2 = #TableHead + ISNULL(#Body, '') + #TableTail
SELECT #Body2
END
I have now set up a SQL job which is supposed to execute this stored procedure and emails the output to a recipient. My SQL Server job runs a T-SQL query (see below):
DECLARE #GeneratedHTML NVARCHAR(MAX);
EXEC ITB_SendEmail #GeneratedHTML = #Body2 OUTPUT
EXEC sp_send_dbmail
#profile_name='BI',
#copy_recipients ='',
#recipients='xxx#yyyy.com',
#subject='ITB',
#body= #GeneratedHTML ,
#body_format = 'HTML' ;
However, the SQL Server job is failing with the following an error message:
Must declare the scalar variable #Body2. [SQLSTATE 42000] (Error 137). The step failed
I cannot figure out the scalar variable declaration issue. What am I doing wrong?
The error is not referring to the variable in your Stored Procedure code if that's what you're thinking.
It's saying you need to DECLARE #Body2 in your Execution Batch. However you have more problems than that. You are trying to access an output parameter of your stored procedure, but in your stored procedure you haven't got an output parameter.
Reading the documentation on Output parameters would be a good start.
Assuming you correctly set #Body2 as an output parameter in your stored procedure, then you simply need to reverse their order in the execution statement:
DECLARE #GeneratedHTML NVARCHAR(MAX);
EXEC ITB_SendEmail #Body2 = #GeneratedHTML OUTPUT
EXEC sp_send_dbmail
#profile_name='BI',
#copy_recipients ='',
#recipients='xxx#yyyy.com',
#subject='ITB',
#body= #GeneratedHTML ,
#body_format = 'HTML' ;