Unable to develop body for email in SQL - sql

I have written a stored procedure where "i have to compare values in two tables and send mail to the users which are not present in second table.
I have to automate this report .
But issue comes when i am trying to make mail body for the same.
The mail body is to be taken from table record ie column name REQ_Approval_EMAILBODY.Also the Recipient id has to be taken from table records ie cloumn name REQ_Approval_EMAILID.
This query has to execute for all the records one by one with respective email ID from table.
Please help me to sort out his.
Thanks in advance
CREATE PROCEDURE Email_Daily
AS
BEGIN
DECLARE #bodynew VARCHAR(Max)
DECLARE #query1 VARCHAR(Max)
DECLARE #Para VARCHAR(Max)
DECLARE #query2 VARCHAR(Max)
DECLARE #query3 VARCHAR(Max)
DECLARE #query5 VARCHAR(Max)
DECLARE #Yesterday VARCHAR(50)
SET #Yesterday = REPLACE(CONVERT(varchar(50),GETDATE()-1,102),'.','-')
DECLARE #TODAY_DDMMYYY VARCHAR(50)
SET #TODAY_DDMMYYY = REPLACE(CONVERT(varchar(50),GETDATE()-1,6),' ','-')
SELECT * into #Temp3_New_Table
FROM(
SELECT [MessageIdentifier]
,[MessageIdentifier_Archive]
,CONVERT(DATE,REQ_SentDate) AS REQ_SentDate
,[REQ_Token]
,[REQ_Approval_Number]
,[REQ_Order_Number]
,[REQ_Document_Number]
,[REQ_Approval_EMAILID]
,[REQ_Approval_EMAILBODY]
,[REQ_Approval_EMAIL_Subject]
,[RES_Date]
,[IsValid]
,[Response_MessageIdentifier]
,[ReSubmit_Count]
,'0' as Flag
FROM [SAEI].[dbo].[Approval_EMAIL_LOG]
where CONVERT(DATE,REQ_SentDate) = #Yesterday
and res_date is null
and req_approval_number+req_order_number+req_document_number not in
(SELECT
[RES_Approval_Number]+[RES_Order_Number]+[RES_Document_Number]
FROM [SAEI].[dbo].[Approval_Response_WEB_LOG]))as Tr
set #query5='select * from #Temp3_New_Table'
set #para='<p style="font-family:arial; font-size:14px">
Dear Team,
</br>
</br>
</br>
</p>'
Set #bodynew = #PARA
DECLARE #subjects VARCHAR(200)
DECLARE #FileAttachment VARCHAR(400)
DECLARE #Recipients VARCHAR(MAX)
DECLARE #copy VARCHAR(MAX)
set #Recipients='select [REQ_Approval_EMAILID] from #Temp3_New_Table'
drop table #Temp3_New_Table
End

try this
select #para = concat('<p style="font-family:arial; font-size:14px">Dear Team,</br></br>', [REQ_Approval_EMAILBODY],'</br></p>')
from #Temp3_New_Table
{where condition}
EDIT
if you want a cursor then you can try this
DECLARE evilCurse CURSOR FOR
SELECT [REQ_Approval_EMAILID]
,[REQ_Approval_EMAILBODY] = concat('<p style="font-family:arial; font-size:14px">Dear Team,</br></br>', [REQ_Approval_EMAILBODY],'</br></p>')
,[REQ_Approval_EMAIL_Subject]
FROM [SAEI].[dbo].[Approval_EMAIL_LOG]
where CONVERT(DATE,REQ_SentDate) = #Yesterday
and res_date is null
and req_approval_number+req_order_number+req_document_number not in
(SELECT [RES_Approval_Number]+[RES_Order_Number]+[RES_Document_Number]
FROM [SAEI].[dbo].[Approval_Response_WEB_LOG])
OPEN evilCurse
FETCH NEXT FROM evilCurse
INTO #Recipients, #bodynew, #subjects
WHILE ##FETCH_STATUS = 0
BEGIN
--do what ever you want to do to here
FETCH NEXT FROM evilCurse
INTO #Recipients, #bodynew, #subjects
END
CLOSE evilCurse;
DEALLOCATE evilCurse;

Related

SQL Need to restrict the result of openquery based on column value database

I am using the below open query to fetch the data from the linked server
select * from openquery(HH2, 'select * from "!Root"."!All".RAWDATA' )
WHERE quality = 0 and TAGNAME LIKE '%OBTS_data%' AND TIMESTAMP <= '2022-10-10 13:27'
I need to restrict it with the respect to the database values
means that once all the items from the database value are available in one column the query should stop executing.
Query output is like
The database looks like
I have been able to rewrite the query with some other function example as below
USE Alarm
DECLARE #Tag nVARCHAR(100)
DECLARE db_cursor CURSOR FOR
SELECT Tagname FROM OBTS_Tags
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #Tag
DROP TABLE T1
create table T1
(
TAGNAME nVarchar(100),
TIMESTAMP datetime,
QUALITY VARCHAR(50),
VALUE Bit
)
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #tag
DECLARE #SQL as nVarchar(max),
#Time as varchar(max),
#LinkedServer varchar(100),
#FSQL as nVarchar(max),
#TSQL NVARCHAR(1000);
SET #Time = '2022-10-13 13:27'
SET #LinkedServer = 'HH2'
SET #SQL = 'SELECT TOP 1 * FROM OPENQUERY('+ #LinkedServer + ','''
SET #TSQL = 'select * from "!Root"."!All".RAWDATA WHERE quality = 0 and TAGNAME = '''''+#Tag+''''' AND TIMESTAMP <= '''''+#Time+''''''')';
SET #FSQL = '('+(#SQL+#TSQL)+') ORDER BY TIMESTAMP DESC'
PRINT #FSQL
INSERT INTO T1
EXEC (#FSQL)
FETCH NEXT FROM db_cursor INTO #Tag
END
CLOSE db_cursor
DEALLOCATE db_cursor

Declare a Cursor From a Table as Variable (In the Select-Statement)

I want to create a SP that have 2 String parameters for 2 table names. In the SP I use dynamic SQL to modify one of the tables, but the other is inside a cursor, and I cant use dynamic SQL after the "FOR"
ALTER PROCEDURE NameProcedure #SourceTable VARCHAR(100),#DestinationTable VARCHAR(100)
AS
BEGIN
DECLARE #AddressSource VARCHAR(100), #AddressDestination VARCHAR(100)
SELECT #AddressSource = '[Test_Toa].[dbo].[' + #SourceTable + ']'
SELECT #AddressDestination = '[Test_Toa].[dbo].[' + #DestinationTable + ']'
--Source Table columns
DECLARE #id int, #idmercado int, #idcadena int, #barcode nvarchar(255),#Complete_P nvarchar(MAX)
DECLARE #Cursor CURSOR
SET #Cursor = CURSOR FOR
--HEREE ITS MY PROBLEM :(!!!!!
SELECT id, idmercado, idcadena, barcode, precios + ',' FROM #AddressSource
OPEN #Cursor
FETCH NEXT
FROM #Cursor INTO #id,#idmercado,#idcadena,#barcode,#Complete_P
WHILE ##FETCH_STATUS = 0
BEGIN
--bla bla code
FETCH NEXT
FROM #Cursor INTO #id,#idmercado,#idcadena,#barcode,#Complete_P
END
CLOSE #Cursor
DEALLOCATE #Cursor
END
I just want to declare a cursor for the table that the user gives
Well, you need to write a dynamic sql statement. Just as an hint. You can copy the values from your given source table into a temp table, generate a cursor on the temp table, iterate through it and deallocate the cursor afterwards and drop the temp table. :-)
Here a short demo code:
DECLARE #sql nvarchar(max), #sourceTable nvarchar(255)
CREATE TABLE dbo.t1(id int, name nvarchar(200))
CREATE TABLE dbo.t2(id int, name nvarchar(200))
SET #sourceTable = N'dbo.t1'
CREATE TABLE #temp(id int, name nvarchar(200))
SET #sql = N'
INSERT INTO #temp(id,name)
SELECT id, name
FROM '+#sourceTable
EXEC(#sql)
DECLARE cur CURSOR FOR
SELECT id, name
FROM #temp
OPEN cur
DECLARE #id int, #name nvarchar(200)
FETCH NEXT FROM cur INTO #id, #name
WHILE ##fetch_status = 0 BEGIN
SELECT #id, #name -- demo output
FETCH NEXT FROM cur INTO #id, #name
END
-- cleanup
CLOSE cur
DEALLOCATE cur
DROP TABLE dbo.t1
DROP TABLE dbo.t2
DROP TABLE #temp
Beware, I just have written this in notepad without any database. But I'm quite sure it does it's job.
This just works if all available variants of #sourceTable have the same column specification. If not, you need to extract the needed columns from information schema and build a more dynamic code.

Dynamic SQL Result INTO #Temp Table

I have to Execute a dynamic SQL SELECT Query And put Results into a #TempTable.
DECLARE #StateId CHAR(3)='StateID';
DECLARE #DeptId CHAR(15)='DeptID';
DECLARE #Query VARCHAR(MAX)='Select Columns With Joins Passed From Front End'
DECLARE #Where VARCHAR(500);
DECLARE #FinalQuery VARCHAR(MAX)='';
SET #Where='Some Where Condition';
SET #FinalQuery='SELECT '+#Query+' '+#Where+''
EXEC(#FinalQuery) -- Want To INSERT THIS Result IN SOME `#TempTable`
-- SO that I can perform Some Operations On `#TempTable`
ALSO No Of columns returned From Dynamic SQL SELECT Are Dynamic.
Thanks,
try the below example
DECLARE #StateId CHAR(3)='StateID';
DECLARE #DeptId CHAR(15)='DeptID';
DECLARE #Query VARCHAR(MAX)='*' -- here you pass your query
DECLARE #Where VARCHAR(500);
DECLARE #FinalQuery VARCHAR(MAX)='';
SET #Where='from tablename where condition';
SET #FinalQuery='SELECT '+#Query+' INTO #temptablename '+#Where;
EXEC(#FinalQuery)
Note
:If you need to use temtable after sp execution then use ## rather than # then we can access it or we can use persistent temporary table
Please make sure that your query statements is correctly.
Try this in your stored procedure and check the output results ( copy the result and execute it)
....
SET #FinalQuery='SELECT '+#Query+' '+#Where+'
PRINT(#FinalQuery)
....
You can use the SQL Profiler tool to debug
Try this...
First create the temp table which you need for further calculation.
CREATE TABLE #TEMP
(
STATEID INT,
DEPTID INT
)
DECLARE #STATEID CHAR(10)='STATEID';
DECLARE #DEPTID CHAR(15)='DEPTID';
DECLARE #QUERY VARCHAR(MAX)='INSERT INTO #TEMP_TABLE
SELECT COLUMNS WITH JOINS PASSED FROM FRONT END'
DECLARE #WHERE VARCHAR(500);
DECLARE #FINALQUERY VARCHAR(MAX)=''
SET #WHERE='SOME WHERE CONDITION'
SET #FINALQUERY=+#QUERY+' '+#WHERE+'' -- REMOVED SELECT
EXEC(#FINALQUERY)

procedure that returns varchar

I tried to make a function that returns varchar, but I can't because I'm using CREATE TABLE inside, and when I'm creating it with a procedure I can't return a value.
I wanted to know if you have some advice.
I made this just to make a string with emails separated by ";" so I can have all the "manager" mails in one varchar (for the recipients).
ALTER procedure [dbo].[Manager_email]
AS
BEGIN
declare #mails varchar (max),
#number_of_mails int,
#counter int
set #counter=2
create table #temp ( id int identity, email varchar(30))
insert into #temp (email)
select Email
from hr.Employees
where lower (EmpRole) like 'manager'
set #number_of_mails=##ROWCOUNT
set #mails = (select email from #temp where id =1 ) + ';'
while #counter <= #number_of_mails
BEGIN
set #mails = #mails + (select email from #temp where id =#counter ) + ';'
set #counter = #counter+1
END
drop table #temp
return cast (#mails as varchar (200))
END
You can only return integer value back from the procedure, If you want to return varchar value from procedure its good to make use of output variable in procedure.
Example
CREATE PROCEDURE Sales.uspGetEmployeeSalesYTD
#SalesPerson nvarchar(50),
#SalesYTD money OUTPUT
AS
SET NOCOUNT ON;
SELECT #SalesYTD = SalesYTD
FROM Sales.SalesPerson AS sp
JOIN HumanResources.vEmployee AS e ON e.BusinessEntityID = sp.BusinessEntityID
WHERE LastName = #SalesPerson;
RETURN
like in above procedure return #SalesYTD from procedure.
you can check full post on MSDN : Returning Data by Using OUTPUT Parameters
You can use function instead
CREATE FUNCTION Manager_email ()
RETURNS varchar(max)
AS
BEGIN
declare #email varchar(30)
declare #emails varchar(max)
set #emails = ''
declare cur cursor for
select Email
from hr.Employees
where lower (EmpRole) like 'manager'
open cur
fetch next from cur into #email
while ##fetch_status = 0
begin
set #emails = #emails + #email + ';'
fetch next from cur into #email
end
close cur
deallocate cur
return #emails
END
You can use table variable instead of temporary table. In that case you can continue to use UDF.

Update a Table by Passing Table Name, ColumnName as a Variable Using Cursor

I want to Update a Table. I am getting Table Name and Column Name as a XML DataSet from the Front End. I have written One Cursor for that. But it throws error. Below is my Cursor
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[PMT_Formstatus_Update_Test]
(
#XMLTableNames VARCHAR(MAX)
)
AS
BEGIN
DECLARE #docHandle INT, #ErrorMessage VARCHAR(200), #doc VARCHAR(200)
SET #doc = '<?xml version="1.0" encoding="iso-8859-1" ?>'
DECLARE #Names TABLE
(
TName VARCHAR(50),
CName VARCHAR(50),
IDField VARCHAR(50),
FunctionID INT,
ID INT,
StatusID INT
)
SET #XMLTableNames = #doc + #XMLTableNames
EXEC sp_xml_preparedocument #docHandle OUTPUT, #XMLTableNames
INSERT INTO #Names
SELECT * FROM
OPENXML(#docHandle,'NewDataSet/NameDetails',2)
WITH
(
TName VARCHAR(50),
CName VARCHAR(50),
IDField VARCHAR(50),
FunctionID INT,
ID INT,
StatusID INT
)
DECLARE #FunctionID INT
DECLARE #StatusID INT
DECLARE #ID INT
DECLARE #TableName VARCHAR(50)
DECLARE #ColumnName VARCHAR(50)
DECLARE #IDField VARCHAR(50)
DECLARE #getTables CURSOR
SET #getTables = CURSOR FOR
SELECT FunctionID, TName, CName, StatusID, IDField, ID FROM #Names
OPEN #getTables
FETCH NEXT
FROM #getTables INTO #FunctionID, #TableName, #ColumnName, #StatusID, #IDField, #ID
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE #TableName SET #ColumnName = 3 WHERE #IDField = #ID
FETCH NEXT
FROM #getTables INTO #FunctionID, #TableName, #ColumnName, #StatusID, #IDField, #ID
END
CLOSE #getTables
DEALLOCATE #getTables
END
How to write Update Query in this case? Please I need all your suggestions...
You need to concatenate them as string then call EXEC('')
EXEC ('UPDATE TableName SET ColumnName1 = 3 WHERE ColumnName2= Value')
Simple Dynamic SQL Example:
DECLARE #SQL NVARCHAR(max),#TableName VARCHAR(128),#ColumnName1 VARCHAR(128),#ColumnName2 VARCHAR(128),#Value NVARCHAR(MAX),#NewValue NVARCHAR(MAX)
SET #TableName='User'
SET #ColumnName1='Session_Id'
SET #ColumnName2='Session_Id_Old'
SET #Value=''''+CAST(NEWID() as NVARCHAR(50))+''''
SET #NewValue=''''+CAST(NEWID() as NVARCHAR(50))+''''
SET #SQL=
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
'UPDATE [#TableName] SET [#ColumnName1] = #NewValue WHERE [#ColumnName2]= #Value','#TableName',#TableName),
'#ColumnName1',#ColumnName1),'#Value',#Value),'#NewValue',#NewValue),'#ColumnName2',#ColumnName2)
EXECUTE(#SQL)
You should add apostrophes to both sides of old/new values if data types are strings
You can hopefully see why what you've written doesn't work, since it's an update statement to execute against a table variable, which affects no actual columns in that table:
declare #TableName table (ID int not null)
declare #ColumnName1 int
declare #ColumnName2 int
declare #Value int
UPDATE #TableName SET #ColumnName1 = 3 WHERE #ColumnName2= #Value
One means to try and achieve what you're doing are dynamic SQL. It's ugly (and will be more so if the data types in the columns vary). There's no real "meta-programming" system built into T-SQL.