Create json object in SQL stored procedure based on input parameters - sql

I need to create a json object in a stored procedure based on input parameters. The following works, but it's not very elegant and I am looking for a more elegant solution.
-- adding log entry
declare #logjson nvarchar(max);
set #logjson = concat( '{"InputParameters":[', '{');
set #logjson = concat(#logjson, '"MacOwner":"', #Owner, '",');
set #logjson = concat(#logjson, '"EMS":"', #EMS, '",');
set #logjson = concat(#logjson, '"AXBomId":"', #AXBomId, '",');
set #logjson = concat(#logjson, '"Serial":"', #SerialId, '",');
set #logjson = concat(#logjson, '"Device":"', #AXItem, '",');
set #logjson = concat(#logjson, '"HWDevice":"', #HWDevice, '",');
set #logjson = concat(#logjson, '"TestPCHostName":"', #TestPCHostName, '",');
set #logjson = concat(#logjson, '"TestSWVersion":"', #TestSWVersion, '"'); --Last parameter no comma
set #logjson = concat(#logjson, '}],');
set #logjson = concat(#logjson, '"OutputParameters":[','{');
set #logjson = concat(#logjson, '"MACAddress":"', #MACAddress, '"');
set #logjson = concat(#logjson, '}');
set #logjson = concat(#logjson, ']' );
set #logjson = concat(#logjson, '}');
I tried to use the SELECT xxxxx FOR JSON AUTO - but this requires at least one table in the select statement.

You can select from a subquery. For example
declare #Owner varchar(5) ='ow123', #AXBomId int =11
select * from (
select #Owner as MacOwner, #AXBomId as AXBomId
) t
for json auto
returns
[{"MacOwner":"ow123","AXBomId":11}]

Related

Why using Sql parameters are not supported?

If I use the parameters to set the value in order to update the fields, nothing has been updated, but if I assign the value to the field directly, everything works fine.
Here is my sql script with parameters that won't work:
DECLARE #ItemValue NUMERIC(2,1) = 0.0,
#ItemName NVARCHAR = NULL,
#RuleID INT,
#IsValid BIT
SET #ItemValue =9
SET #ItemName = 'chbWorkingTimePerDay'
SET #RuleID = 1
SET #IsValid = 1
UPDATE hrms.RuleValue
SET ItemValue = #ItemValue,
IsValid = #IsValid
FROM hrms.RuleItem RI
JOIN hrms.RuleValue RV
ON RI.RuleItemID = RV.RuleItemID
WHERE RI.ItemName = #ItemName
AND RV.RuleID = #RuleID
Here is my sql script without parameters that works:
UPDATE hrms.RuleValue
SET ItemValue = 8.0,
IsValid = 1
FROM hrms.RuleItem RI
JOIN hrms.RuleValue RV
ON RI.RuleItemID = RV.RuleItemID
WHERE RI.ItemName = 'chbWorkingTimePerDay'
AND RV.RuleID = 1
#ItemName NVARCHAR = NULL will translate to #ItemName NVARCHAR(1) = NULL, which will cut off the string. You need to set NVARCHAR size.
So use:
#ItemName NVARCHAR(100) = NULL
instead of:
#ItemName NVARCHAR= NULL
SqlFiddle is available here.

AmpScript issue with IF Statement

I am trying to do a lookup to two different data extensions in exact target using ampscript. Please find the sample code I am trying .
%%[
Var #rows
Set #rows=LookupRows("DataExtensionOne","Lead Owner","Nick")
FOR #y = 1 TO RowCount(#rows) DO
Set #currentRow = Row(#rows,#y)
Set #value = FIELD(#currentRow ,"LeadId")
Set #secondDERows = LookupRows("DataExtensionTwo","Gender","Male")
FOR #x = 1 TO RowCount(#secondDERows) DO
Set #currentRowInSecDE = Row(#secondDERows,#x)
Set #secValue = FIELD(#currentRowInSecDE ,"LeadId")
IF #value == #secValue THEN
Set #FirstName = FIELD(#currentRowInSecDE ,"FirstName")
/* Need to break out of the loop */
]%%
The If condition check seems to fail #value == #secValue .
It doesnt fetch any value for the #FirstName. And what statement should be used to break out of IF loop ?
Has anyone come across similar problems ? Please do let me know.
As far as I am aware, ampscript does not have a break operator.
In this case, I would set up a boolean value that is checked to be false at the start of each loop and is set to True when you find a match. This way once you have matched you'll still run through the rest of the loop but noting will happen within them.
%%[
Var #rows
Set #found_result = False
Set #rows=LookupRows("DataExtensionOne","Lead Owner","Nick")
FOR #y = 1 TO RowCount(#rows) DO
if not #found_result then
Set #currentRow = Row(#rows,#y)
Set #value = FIELD(#currentRow ,"LeadId")
Set #secondDERows = LookupRows("DataExtensionTwo","Gender","Male")
FOR #x = 1 TO RowCount(#secondDERows) DO
if not #found_result then
Set #currentRowInSecDE = Row(#secondDERows,#x)
Set #secValue = FIELD(#currentRowInSecDE ,"LeadId")
IF #value == #secValue THEN
Set #FirstName = FIELD(#currentRowInSecDE ,"FirstName")
Set #found_result = True
ENDIF
endif
NEXT #x
endif
NEXT #y
]%%
%%[
Var #rows
Set #found_result = False
Set #rows=LookupRows("DataExtensionOne","Lead Owner","Nick")
FOR #y = 1 TO RowCount(#rows) DO
if #found_result == "TRUE" then
Set #currentRow = Row(#rows,#y)
Set #value = FIELD(#currentRow ,"LeadId")
Set #secondDERows = LookupRows("DataExtensionTwo","Gender","Male")
FOR #x = 1 TO RowCount(#secondDERows) DO
if #found_result == "TRUE" then
Set #currentRowInSecDE = Row(#secondDERows,#x)
Set #secValue = FIELD(#currentRowInSecDE ,"LeadId")
IF #value == #secValue THEN
Set #FirstName = FIELD(#currentRowInSecDE ,"FirstName")
Set #found_result = True
ENDIF
endif
NEXT #x
endif
NEXT #y
]%%

Define a SQL variable with Database Name

With this T-SQL query I define a variable #InDate with some date.
SET
#InDate = (SELECT MIN(bt.CreateDate) AS [INDATE]
FROM
mydatabase.dbo.BuyTransaction bt
LEFT JOIN
mydatabase.dbo.TransactionExtraFields tef ON bt.TransDocument = tef.TransDocument
AND bt.TransSerial = tef.TransSerial
AND bt.TransDocNumber = tef.TransDocNumber
AND ExtraFieldID = 1
WHERE
bt.TransDocument = 'FRM' AND tef.TextAnswer = #NumPI
AND bt.TransStatus = 0)
But now I need to change the Database name by another variable. I try something like that to make a string in a variable which will be executed
SET #InDate = '(SELECT MIN(bt.CreateDate) AS [INDATE]
FROM mydatabase.dbo.BuyTransaction bt
LEFT JOIN mydatabase.dbo.TransactionExtraFields tef ON bt.TransDocument = tef.TransDocument AND bt.TransSerial = tef.TransSerial AND bt.TransDocNumber = tef.TransDocNumber AND ExtraFieldID = 1
WHERE bt.TransDocument = ''FRM'' AND tef.TextAnswer = '''+#NumPI+''' AND bt.TransStatus = 0)'
EXECUTE #InDate
But my problem is how can I get the execute result into a variable again. Something like SET #InDate2 = EXECUTE #InDate is not working...
Any idea?
Use sp_executesql. I think the syntax in your case is something like:
declare #InDate date;
declare #sql nvarchar(max);
set #sql = N'SELECT #InDate = MIN(bt.CreateDate)
FROM mydatabase.dbo.BuyTransaction bt
LEFT JOIN mydatabase.dbo.TransactionExtraFields tef ON bt.TransDocument = tef.TransDocument AND bt.TransSerial = tef.TransSerial AND bt.TransDocNumber = tef.TransDocNumber AND ExtraFieldID = 1
WHERE bt.TransDocument = ''FRM'' AND tef.TextAnswer = '''+#NumPI+''' AND bt.TransStatus = 0';
exec sp_executesql #sql, N'#InDate date output', #InDate = #InDate output;
You can also make #NumPI a parameter as well.
The documentation for sp_executesql is here.
I have done this type of issue.
Please check the sample code. Its working for me. Please change according.
DECLARE #SQLString NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #IntVariable INT
DECLARE #Lastlname varchar(30) = 'col10 ' -- this variable use for input in sp
SET #SQLString = N'SELECT #LastlnameOUT = '+#Lastlname+'
FROM TempStoreExcelData '
SET #ParmDefinition = N'#level tinyint,
#LastlnameOUT varchar(30) OUTPUT'
SET #IntVariable = 35
EXECUTE sp_executesql
#SQLString,
#ParmDefinition,
#level = #IntVariable,
#LastlnameOUT=#Lastlname OUTPUT
SELECT #output = #Lastlname
select #output

Stored Procedure sends two emails

EDIT
My previous posting on this subject involved specific transactions within the procedure which are no longer used and the error now only seems to occur in a very specific set of circumstances when I use an invalid user name to our companies email address badname#ourcompany.co.uk
The agent runs a stored procedure every ten minutes to send out emails. If it finds a new record then it sends a mail.
Noticed some strange behavior - if the TO field is correct but the BCC is an invalid email address but uses our valid company domain name (e.g. rubbishPart#ourcompany.co.uk) then the stored procedure sends out two emails to the TO. The domain name needs to be our company's domain name to get this behavior ...if I change the domain to gmail.com then only one mail goes out.
Why is this happening?
How do I change this behavior?
Is the Catch in this procedure redundant?
Here is the procedure:
BEGIN TRY
DECLARE #Exit TINYINT = 0
WHILE #Exit = 0
BEGIN
DECLARE #MailIdFound INT =
(
SELECT CASE
WHEN MIN(EmailId) IS NULL THEN 0
ELSE MIN(EmailId)
END
FROM WH.dbo.EmailQueue
WHERE DateEmailKey IS NULL
)
IF #MailIdFound = 0
BEGIN SET #Exit = 1 END --exit here as
ELSE
BEGIN --send the mail here
DECLARE #DateEmailKey INT
DECLARE #EmailBCC NVARCHAR(1000)
DECLARE #EmailTO NVARCHAR(1000)
DECLARE #EmailCC NVARCHAR(1000)
DECLARE #EmailBody NVARCHAR(MAX)
DECLARE #EmailImportance VARCHAR(6)
DECLARE #EmailSubject NVARCHAR(1000);
WITH myMostUrgentMail_cte
AS
(
SELECT TOP 1
DateEmailKey,
EmailBCC,
EmailTO,
EmailCC,
EmailBody,
EmailImportance,
EmailSubject
FROM WH.dbo.EmailQueue
WHERE EmailId = #MailIdFound
)
SELECT #DateEmailKey = DateEmailKey,
#EmailTO = EmailTO,
#EmailCC = EmailCC,
#EmailBCC = EmailBCC,
#EmailBody = EmailBody,
#EmailSubject = EmailSubject
FROM myMostUrgentMail_cte;
SET #EmailBody = #EmailBody + '<html>

<span style=''font-size:11.0pt;font-family:"Calibri","sans-serif"; color:black''><p><b>blah blah</b></p></span></html>'
EXEC msdb..sp_send_dbmail
#recipients = #EmailTO,
#copy_recipients = #EmailCC,
#blind_copy_recipients = #EmailBCC,
#subject = #EmailSubject,
#Importance = #EmailImportance,
#body_format = 'html',
#body = #EmailBody
UPDATE x
SET x.DateEmailKey = (CONVERT(CHAR(8),GETDATE(),(112))),
x.DateEmailTime = (CONVERT([time](7),left(CONVERT([char](12),GETDATE(),(114)),(8)),(0)))
FROM WH.dbo.EmailQueue x
WHERE x.EmailId = #MailIdFound
END
END
END TRY
BEGIN CATCH
-- handle error here
EXEC msdb..sp_send_dbmail
#recipients = 'ME#ME.com;'
, #subject = 'ERROR OCCURED DURING EMAIL CREATION'
, #body_format = 'html'
, #body = 'ERROR OCCURED'
UPDATE x
SET x.ErrorOccured = 1
FROM WH.dbo.EmailQueue x
WHERE x.EmailId = #MailIdFound
END CATCH;

set ansi_warnings off not working

Why do I still receiving in the emails: Warning: Null value is eliminated by an aggregate or other SET operation. If I have set the ansi_warnings off
set ansi_warnings off
set #subj = 'xxx'
set #msg = 'xxx' + char(13) + char(10)
set #q = 'select LSRNbr, trh.ShipperId, InvoiceNbr, Qty, count(LotSerNbr) as QtyRcvd
from tblRIM2_Header trh (nolock)
left outer join tblRIM2_SerialsFromFile trs (nolock) on trh.ShipperId = trs.ShipperId
where isnull(Completed,0) = 0
group by trh.ShipperId, LSRNbr, InvoiceNbr, Qty'
exec master.dbo.xp_sendmail
#recipients = 'xxx',
#subject = #subj ,
#query = #q,
#message = #msg,
#attach_results = FALSE,
#dbuse = 'GlobalQCS'
set ansi_warnings on
You have to put set ansi_warnings off inside #q:
set #q = 'set ansi_warnings off select LSRNbr, trh.ShipperId, ...`