Using SQL Server 2012 Express.
I'm building a communications system which emails end users some notifications about upcoming work. I have a table that stores merge field placeholders and the database field which should populate the data into these placeholders.
I've tried to write a function where I can supply an input string with these placeholders, a unique identifier for that user/machine, and the tenantID, and have it return the string with all the placeholder values replaced with the user's/machine's database values.
I'm running into the error:
Only functions and some extended stored procedures can be executed from within a function.
which I've googled and understand why, however I don't know how else I can achieve what I'm trying to do without doing it the way I'm doing it.
The code I've written is as follows:
CREATE TABLE [dbo].[CommsFields]
(
[ID] [BIGINT] IDENTITY(1,1) NOT NULL,
[TenantID] [BIGINT] NOT NULL,
[Placeholder] [VARCHAR](255) NOT NULL,
[DBField] [VARCHAR](255) NOT NULL
)
INSERT INTO CommsFields (TenantID, Placeholder, DBField)
VALUES (1, '@@Email', 'u_PrimarySMTP')
CREATE TABLE [dbo].[AllMUs]
(
[MUID] BIGINT,
u_PrimarySMTP VARCHAR(255)
)
INSERT INTO AllMUs (MUID, u_PrimarySMTP)
VALUES (28228, '[email protected]')
CREATE FUNCTION DoFieldMerge
(@SourceString NVARCHAR(MAX),
@MUID BIGINT,
@TenantID BIGINT)
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE @ResultString NVARCHAR(MAX)
DECLARE @sql NVARCHAR(MAX)
DECLARE @PHID AS INT
DECLARE @PHCursor AS CURSOR
SET @sql = CONCAT('DECLARE @Tenant bigint = ', @TenantID, '; DECLARE @MU bigint = ', @MUID, '; DECLARE @ResultString2 nvarchar(MAX) = ''', @SourceString, ''';')
SET @PHCursor = CURSOR FOR
SELECT ID FROM CommsFields
OPEN @PHCursor;
FETCH NEXT FROM @PHCursor INTO @PHID
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = CONCAT(@sql, 'SET @ResultString2 = replace(@ResultString2, ''', (SELECT Placeholder FROM CommsFields WHERE ID = @PHID AND TenantID = @TenantID), ''', (SELECT ISNULL(', (SELECT DBField FROM CommsFields WHERE ID = @PHID AND TenantID = @TenantID), ', '''') FROM AllMUs WHERE MUID = ', @MUID, ' AND TenantID = ', @TenantID, '));')
FETCH NEXT FROM @PHCursor INTO @PHID
END
CLOSE @PHCursor;
DEALLOCATE @PHCursor;
--SET @ResultString = @sql
EXEC sp_executesql @sql, N'@ResultString2 nvarchar(MAX) output', @ResultString output;
RETURN @ResultString
END
GO
SELECT dbo.DoFieldMerge('test @@Email', 28228, 1)
I expect the output to be 'test [email protected]' but instead I get the error
Only functions and some extended stored procedures can be executed from within a function
If I comment out the 'exec' command near the end, and un-comment the 'SET' command above it, I get the SQL output which I was trying to achieve, and if I run this I get a correct result, but I need to run the contents of @sql
within the function and return just the resulting @ResultString
.
I've also tried searching for a code snippet that acts as a custom column merger in SQL, but I'm getting so many results which are nothing to do with what I'm really wanting.
The answer here was to instead use a stored procedure with an output parameter. My final SQL ended up as follow:
CREATE PROCEDURE [dbo].[DoMerge]
@SourceString nvarchar(MAX)
, @MUID bigint
, @TenantID bigint
, @ResultString nvarchar(MAX) output
AS
BEGIN
SET NOCOUNT ON;
DECLARE @sql nvarchar(MAX)
DECLARE @PHID as INT
DECLARE @PHCursor as CURSOR
SET @sql = CONCAT('DECLARE @Tenant bigint = ', @TenantID, '; DECLARE @MU bigint = ', @MUID, '; DECLARE @ResultString2 nvarchar(MAX) = ''', @SourceString, ''';')
SET @PHCursor = CURSOR FOR
SELECT ID FROM CommsFields
OPEN @PHCursor;
FETCH NEXT FROM @PHCursor INTO @PHID
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = CONCAT(@sql, 'SET @ResultString2 = replace(@ResultString2, ''', (SELECT CONCAT((SELECT TemplateFieldMarker FROM Config), Placeholder) FROM CommsFields WHERE ID = @PHID AND TenantID = @TenantID), ''', (SELECT ISNULL(', (SELECT DBField FROM CommsFields WHERE ID = @PHID AND TenantID = @TenantID), ', '''') FROM AllMUs WHERE MUID = ', @MUID, ' AND TenantID = ', @TenantID, '));')
FETCH NEXT FROM @PHCursor INTO @PHID
END
CLOSE @PHCursor;
DEALLOCATE @PHCursor;
SET @sql = CONCAT(@sql, ' SELECT @ResultString2')
exec (@sql)
END