Why do I get this error in SQL Server? How to fix it? - sql

I am creating a stored procedure to insert to a table. Following would provide my table columns are
Create Table Item
(
ID char(20),
Name varchar(max) NOT NULL,
Brand char(10) NOT NULL,
Category char(10) NOT NULL,
Unit_Of_Measure char(5) NOT NULL,
Price decimal(18,2) NOT NULL,
[Image] image NOT NULL,
Active bit NOT NULL Default('True')
Constraint PK_Item Primary Key (ID),
Constraint FK_Item_Brands Foreign Key (Brand) References Brands(ID),
Constraint FK_Item_Item_Category Foreign Key (Category) References Item_Category(ID),
Constraint FK_Item_Unit_Of_Measure Foreign Key (Unit_Of_Measure) References Unit_Of_Measure(ID)
);
go
Table insert is working fine. Before we go further I need to show the error that I am getting.
Msg 50000, Level 16, State 2, Procedure stpItem, Line 66
Operand type clash: image is incompatible with nvarchar
The above error occurs when I'm executing the command below and after that you would see the stored procedure
exec stpItem '','GG','2','2','2',123.12, null, 'true', 'false'
Stored procedure code:
Create Proc stpItem
#ID varchar(max),
#Name varchar(max),
#Brand varchar(max),
#Category varchar(max),
#UOM varchar(max),
#Price decimal,
#Image Image,
#Active bit,
#Update bit
As
Set Transaction Isolation Level Serializable
Begin Transaction
Begin Try
-- If it is an insertion
IF #Update = 'False'
Begin
Declare #Pre char(1),
#Len int,
#Next int,
#Start int,
#SetKey varchar(max);
Set #SetKey = '';
Select #Pre = Prefix, #Len = [Length], #Next = [Next] From Key_Generation Where Table_Name = 'Item';
Set #Start = 1;
Set #Len = #Len - 1;
While #Start < #Len
Begin
set #SetKey = #SetKey + '0'
set #Start = #Start + 1;
End
Exec('Declare #LID char(20); Set #LID = (select ''' + #Pre + ''' + right(''' + #SetKey + ''' + cast(' + #Next + ' as varchar(' + #Len + ')), ' + #Len + '));' +
'Insert into Item Values (#LID,''' + #Name + ''',''' + #Brand + ''',''' + #Category + ''',''' + #UOM + ''',' + #Price + ',' + #Image + ' ,' + #Active + ');' +
'Update Key_Generation Set [Next] = [Next] + 1 Where Table_Name = ''Item'';');
End
Else
Begin
Update Item
Set Name = #Name,
[Brand] = #Brand,
[Category] = #Category,
[Unit_Of_Measure] = #UOM,
Price = #Price,
[Image] = #Image,
Active = #Active
Where ID = #ID;
End
Commit Transaction;
End Try
Begin Catch
Rollback Transaction;
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT
#ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (#ErrorMessage, -- Message text.
#ErrorSeverity, -- Severity.
#ErrorState -- State.
);
End Catch
Could anyone tell me why I am getting this error, and how to fix this issue?

You are not casting non varchar variables to varchar here:
#Price + ',' + #Image + ' ,' + #Active + ');'
Try:
cast(#price as varchar(max)) + ',' + cast(#image as varchar(max)) + ...

cast(cast(#Image as binary) as nvarchar(max));
I used a nvarchar variable to convert it from outside then use it inside og execution command
Declare #txtImage nvarchar(max);
if #Image IS NULL
Begin Set #txtImage = 'NULL'; END
Else
Begin Set #txtImage = cast(cast(#Image as binary) as nvarchar(max)); END

Related

Getting multi-part identifier "column name" could not be bound error in SQL Server of newer version

I have this code for my stored procedure:
create or alter procedure udpReservationFilter
#FName nvarchar(160),
#LName nvarchar(160),
#Category nvarchar(160),
#Number int,
#TotalCount int OUT,
#ColumnName nvarchar(100) = 'M.Id',
#SortDesc bit = 0,
#Page int = 1,
#PageSize int = 2
as
begin
declare #sqlWhere nvarchar(max) = ''
declare #whereParams nvarchar(1000) = N' #FName nvarchar(160),
#LName nvarchar(160),
#Category nvarchar(160),
#Number int, #OffsetRows int, #PageSize int'
declare #countParams nvarchar(1000) = N' #FName nvarchar(160),
#LName nvarchar(160),
#Category nvarchar(160),
#Number int,
#TotalCount int OUT'
if len(trim(#FName)) > 0
set #sqlWhere += ' AND c.FName like ''%'' + #FName + ''%'' '
if len(trim(#LName)) > 0
set #sqlWhere += ' AND c.LName like #LName '
if len(trim(#Category))> 0
set #sqlWhere += ' AND r.Category like #Category '
if (#Number > 0)
set #sqlWhere += ' AND r.Number = #Number '
---------------- counting total results -------------------
declare #sqlCount nvarchar(1000) = N' select #TotalCount = count(*) from Reservations M '
if len(#sqlWhere) > 0
set #sqlCount = #sqlCount + ' where ' + (SUBSTRING(#sqlWhere, 5 , 60))
exec sp_executesql #sqlCount,
#countParams,
#FName = #FName,
#LName = #LName,
#Category = #Category,
#Number = #Number,
#TotalCount = #TotalCount OUT
declare #sql nvarchar(max) = N' select M.*, c.*, r.Category, r.Number, r.Price, r.Status
from Reservations M, Client c, Rooms r
where M.ClientId=c.ID and M.RoomId=r.Id'
+ #sqlWhere
+ ' order by ' + #ColumnName
+ ' offset #OffsetRows rows fetch next #PageSize rows only'
--M.*, c.*, r.Number, r.category, r.Price, r.status
declare #Offset int = (#Page-1)*#PageSize
if #Offset < 0
set #Offset = 0
exec sp_executesql #sql,
#whereParams,
#FName = #FName,
#LName =#LName,
#Category = #Category,
#Number = #Number,
#OffsetRows = #Offset,
#PageSize = #PageSize
end
I'm getting this error:
The multi-part identifier "column_name" could not be bound.
when executing the query.
declare #cnt int
exec udpReservationFilter
#FName = null,
#LName = null,
#Category = null,
#Number = null,
#TotalCount = #cnt OUT,
#PageSize = 3
When I provide parameters it is above error and gives the matched result this error stops my asp.net core app and if there is no parameters provided its compiling without error
Here is more detailed error :
Msg 4104, Level 16, State 1, Line 5
The multi-part identifier "c.FName" could not be bound.
(1 row affected)

Generate script with INSERT SELECT statements from T-SQL

I have two databases in SQL Server 2014 Express, since a few days ago I am unifying both databases in such a way that there is only one left.
When I have this new database I must pass it to Azure (I don't have any experience using this technology), however, I am doing tests on my local server, so far I have created the whole scheme but I must fill out all the tables to perform tests with my application.
There are 313 tables of which many have more than 200,000 records, my question is, what is the best way to populate the database?
Because at this moment I want to test my local machine, I could fill in the tables through Tasks> Generate Script> Advanced Options (Include only data) but this information will change the day when the migration to Azure is done, therefore I must Do the same process.
So, is it possible to create an INSERT SELECT script so that it does not include records one by one and is as dynamic as possible? For example, you would have to generate an INSERT INTO similar to this:
SET IDENTITY_INSERT [SchemaX].[TableA] ON ;
INSERT INTO [SchemaX].[TableA]
(
[id]
,[fieldA]
,[fieldB]
,[fieldC])
SELECT
[id]
,[fieldA]
,[fieldB]
,[fieldC]
FROM [server].[dbname].[SchemaX].[TableA]
SET IDENTITY_INSERT [SchemaX].[TableA] OFF ;
Some tables have IDENTITY enabled so you would have to recognize which tables are like this and use SET IDENTITY_INSERT when inserting. This way you would have to link the production server and insert the information into the local server.
If there are suggestions or recommendations about another way you are welcome
Has been answered before ...
/****** Object: StoredProcedure [dbo].[procUtils_GenerateInsertProc] Script Date: 03/20/2010 13:06:13 ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[procUtils_GenerateInsertProc]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[procUtils_GenerateInsertProc]
GO
/****** Object: StoredProcedure [dbo].[procUtils_GenerateInsertProc] Script Date: 03/20/2010 13:06:13 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--exec procUtils_GenerateInsertProc 'Whatever'
--exec sp_HelpText procUtils_GenerateInsertProc
CREATE PROCEDURE [dbo].[procUtils_GenerateInsertProc]
#TableName [varchar](50)
WITH EXECUTE AS CALLER
AS
BEGIN -- proc start
SET NOCOUNT ON;
BEGIN TRY --begin try
--FIRST SEARCH THE TABLE WHICH HAD A "Feature" in its name
--SELECT NAME FROM SYS.TABLES WHERE NAME LIKE '%Feature%'
--SELECT column_name from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='Feature' --SELECT * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='Task'
--Decalre a variable to remember the position of the current delimiter
DECLARE #ProcName varchar(1000)
set #ProcName = '[dbo].[procGen_' + #TableName + '_Insert]'
DECLARE #CurrentDelimiterPositionVar INT
DECLARE #PkColumnName varchar(200)
--Decalre a variable to remember the number of rows in the table
DECLARE #Count INT
DECLARE #ColumnName varchar(300);
DECLARE #DataType varchar(50)
DECLARE #IsNullable bit
DECLARE #MaxLength INT
DECLARE #IsComputed BIT
set #IsComputed = 0
DECLARE #IsPrimaryKey BIT
set #IsPrimaryKey = 0
DECLARE #CODESTR VARCHAR(max)
--PRINT DROP PROCEDURE
set #CODESTR = ' '
--Declare the Table variable
DECLARE #ColumnNames TABLE
(
Number INT IDENTITY(1,1), --Auto incrementing Identity column
TableName varchar(300) , --the name of the table
ColumnName VARCHAR(300) , --The string value ,
DataType varchar(50) , --the datatype
IsNullable bit , --should we add =null in front
MaxLength INT , --VARCHAR(LENGHTi)
IsComputed bit , --whether or not this table is computed
IsPrimaryKey bit --whether or not this table is computed
)
--Populate the TABLE variable using some logic
-- SELECT * from INFORMATION_SCHEMA.COLUMNS
INSERT INTO #ColumnNames
(
TableName ,
ColumnName ,
DataType ,
IsNullable ,
MaxLength ,
IsComputed ,
IsPrimaryKey )
SELECT
TableName ,
ColumnName ,
DataType ,
IsNullable ,
MaxLength ,
IsComputed ,
IsPrimaryKey
from viewMeta_TableColumns
--debug where TableName = 'Whatever'
where TableName = #TableName
--SELECT column_name , Data_type , IsNullable , MaxLength
--from INFORMATION_SCHEMA.COLUMNS
--where TABLE_NAME=#TableName
--Initialize the looper variable
SET #CurrentDelimiterPositionVar = 1
--Determine the number of rows in the Table
SELECT #Count=max(Number) from #ColumnNames
--A variable to hold the currently selected value from the table
set #CODESTR = #CODESTR + 'IF OBJECT_ID(''' + #ProcName + ''') IS NOT NULL
BEGIN
DROP PROC ' + #ProcName + '
END
GO'
set #CODESTR = #CODESTR + '
/****** Object: StoredProcedure ' + #ProcName + '*/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE ' + #ProcName + '
#CurUserSessionId [int] ,
#CurPageTypeId [int] ,
#MsgOut [varchar](200) OUTPUT ,
#DebugMsgOut [varchar](200) OUTPUT,
#Ret [int] OUTPUT ,' + CHAR(13)
--#COLUMN_NAME [DATA_TYPE] (MAX_LENGTH) =NULL ,
WHILE #CurrentDelimiterPositionVar <= #Count --1st loop
BEGIN
--Load current value from the Table
SELECT #ColumnName = ColumnName FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar
SELECT #DataType = DataType FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar
SELECT #MaxLength = MaxLength FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar
set #IsNullable = ( select IsNullable FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar )
set #IsPrimaryKey = ( select IsPrimaryKey FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar )
if ( #DataType = 'timestamp' or #IsComputed = 1)
begin
set #CurrentDelimiterPositionVar = #CurrentDelimiterPositionVar + 1
continue
end
set #CODESTR = #CODESTR + '#' + #ColumnName + ' ['+ #DataType + '] '
--ADD THE (200)
IF #MaxLength IS NOT NULL
BEGIN --IF #MaxLength IS NOT NULL
--xml
if #DataType <> 'xml' and #DataType <> 'sql_variant' and
#DataType <> 'text' and #DataType <> 'ntext' and #DataType <> 'image' and
#DataType <> 'hierarchyid' and #DataType <> 'bit' and #DataType <> 'varbinary' and
#DataType <> 'int' and #DataType <> 'uniqueidentifier' and #DataType <> 'tinyint' and
#DataType <> 'timestamp' and #DataType <> 'uniqueidentifier' and #DataType <> 'smallint' and
#DataType <> 'bigint' and #DataType <> 'smallmoney' and #DataType <> 'money' and
#DataType <> 'real' and #DataType <> 'smalldatetime' and #DataType <> 'datetime'
begin --those with()
if #MaxLength <> -1
SET #CODESTR = #CODESTR + '(' + CONVERT(VARCHAR , #MaxLength ) + ')'
else
SET #CODESTR = #CODESTR + '(max)'
end --those with(200)
else
begin
SET #CODESTR = #CODESTR --DO NOTHING
end
END --IF #MaxLength IS NOT NULL
IF #IsNullable = 1
SET #CODESTR = + #CODESTR + ' = NULL '
if #IsPrimaryKey = 1
SET #CODESTR = #CODESTR + ' OUTPUT '
if #CurrentDelimiterPositionVar <> #Count
SET #CODESTR = #CODESTR + ','
--DEBUGGING
--set #CODESTR = #CODESTR + '#ColumnName - ' + #ColumnName
--set #CODESTR = #CODESTR + '#DataType - ' + #DataType
--set #CODESTR = #CODESTR + '#IsNullable - ' + #IsNullable
--set #CODESTR = #CODESTR + '#MaxLength - ' + CONVERT ( VARCHAR , #MaxLength )
set #CODESTR = #CODESTR + CHAR(13)
SET #CurrentDelimiterPositionVar = #CurrentDelimiterPositionVar + 1
END
SET #CODESTR = #CODESTR + '
WITH EXECUTE AS CALLER
AS
BEGIN -- proc start
SET NOCOUNT ON;
BEGIN TRY --begin try
--
set #Ret = 1 --assume false from the beginning
declare #MsgKey [nvarchar](max)
declare #MsgTxt [nvarchar](max)
exec procUtils_GetMsgTxtByKeyAndUserSessionId
#UserSessionId =2 ,
#MsgKey = ''MsgOkTheAddingOfItemIsOk'' ,
#MsgTxt = ''''
set #MsgOut = replace (#MsgTxt , ''{0}'' , ''' + #TableName + ''' )
declare #thisProcName varchar(300)
set #thisProcName= ( SELECT OBJECT_NAME(##PROCID))
'
SET #CurrentDelimiterPositionVar = 1 --START LOOP AGAIN
set #CODESTR = #CODESTR + '
--Action !!!
INSERT INTO [dbo].[' + #TableName + ']( ' + CHAR(13)
--Loop through until all row processing is done
WHILE #CurrentDelimiterPositionVar <= #Count --2nd loop
BEGIN
--Load current value from the Table
SELECT #ColumnName = ColumnName FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar
SELECT #DataType = DataType FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar
SELECT #MaxLength = MaxLength FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar
set #IsNullable = ( select IsNullable FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar )
set #IsPrimaryKey = ( select IsPrimaryKey FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar )
if #IsPrimaryKey = 1
begin -- the primary key
set #PkColumnName = #ColumnName
end --the primary key
if ( #DataType = 'timestamp' or #IsComputed = 1 or #IsPrimaryKey = 1 )
begin
set #CurrentDelimiterPositionVar = #CurrentDelimiterPositionVar + 1
continue
end
--select
if #CurrentDelimiterPositionVar <= #Count
BEGIN
set #CODESTR = #CODESTR + '[' + #ColumnName + ']' --null the codestring var
if #CurrentDelimiterPositionVar <> #Count
set #CODESTR = #CODESTR + ', --type of ' + #DataType + CHAR(13) --WITH COMMA
ELSE
set #CODESTR = #CODESTR + ' --type of ' + #DataType + CHAR(13) --NO COMMA
END -- IF SHOULD PRINT COLUMN
SET #CurrentDelimiterPositionVar = #CurrentDelimiterPositionVar + 1;
END --eof while 2
set #CODESTR = #CODESTR + ') VALUES ( '
--AND START ALL OVER AGAIN
SET #CurrentDelimiterPositionVar = 1
--Loop through until all row processing is done
WHILE #CurrentDelimiterPositionVar <= #Count --WHILE 3
BEGIN
--Load current value from the Table
SELECT #ColumnName = ColumnName FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar
SELECT #DataType = DataType FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar
SELECT #MaxLength = MaxLength FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar
set #IsNullable = ( select IsNullable FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar )
set #IsPrimaryKey = ( select IsPrimaryKey FROM #ColumnNames
WHERE Number = #CurrentDelimiterPositionVar )
if ( #DataType = 'timestamp' or #IsComputed = 1 or #IsPrimaryKey = 1)
begin
set #CurrentDelimiterPositionVar = #CurrentDelimiterPositionVar + 1
continue
end
set #CODESTR = #CODESTR + '#' + #ColumnName
if #CurrentDelimiterPositionVar <= #Count
BEGIN
IF #CurrentDelimiterPositionVar <> #Count
set #CODESTR = #CODESTR + ' , --type of ' + #DataType --all others with comma
else
set #CODESTR = #CODESTR + ' --type of ' + #DataType --the last one without comma
END -- IF SHOULD NOT PRINT COLUMN
--increase the counter
set #CODESTR = #CODESTR + CHAR(13)
SET #CurrentDelimiterPositionVar = #CurrentDelimiterPositionVar + 1;
END
set nocount off
SET #CODESTR = #CODESTR + ')
SET #' + #pkColumnName + ' = ##IDENTITY
set #Ret = ##ERROR
set #DebugMsgOut = ''TODO:REMOVE INSERT OK ''
END TRY
BEGIN CATCH
EXEC #ret = [dbo].[procUtils_GetMsgTxtByKeyAndUserSessionId]
#UserSessionId = 2,
#MsgKey = N''ErrorMsgMenuRetrievalFailed'',
#MsgTxt = #MsgOut OUTPUT
set #ret = 1
set #msgOut = #MsgTxt
set #debugMsgOut = '' Error number: '' + CAST(ERROR_NUMBER() AS varchar(100)) +
''Error message: '' + ERROR_MESSAGE() + ''Error severity: '' +
CAST(ERROR_SEVERITY() AS varchar(10)) +
''Error state: '' + CAST(ERROR_STATE() AS varchar(100)) +
''XACT_STATE: '' + CAST(XACT_STATE() AS varchar(100))
-- record the error in the database
set #debugMsgOut = #debugMsgOut + #msgOut
INSERT INTO [dbo].[LogStore] ( [Date],[Thread],[Level],[Logger],[Message])
values ( getdate() , N''8'', N''DEBUG'', #thisProcName , #debugMsgOut )
END CATCH
END --procedure end
GO
'
print #codestr
END TRY --end try
BEGIN CATCH
print ' Error number: ' + CAST(ERROR_NUMBER() AS varchar(100)) +
'Error message: ' + ERROR_MESSAGE() + 'Error severity: ' +
CAST(ERROR_SEVERITY() AS varchar(1000)) +
'Error state: ' + CAST(ERROR_STATE() AS varchar(100)) +
'XACT_STATE: ' + CAST(XACT_STATE() AS varchar(100))
END CATCH
END --procedure end
--USE [Gaf]
--GO
--SELECT NAME FROM SYS.tables where name like '%Msg%'
--EXEC [dbo].[procUtils_GenerateInsertProc] #TableName = N'Whatever'
GO

Incorrect syntax near '=' while trying to call a stored procedure in T-sql

I am calling a stored procedure called Searchprocedure. I get an error at line where I am calling it. I have not made any changes to the parameters passed in the procedure and it was called just fine with same calling statement earlier.
Exec SearchProcedure #firstname = 'Simran', #middlename = 'kaur', #lastname = 'Khurana', #City = 'Delhi'
What's wrong with the syntax that is gives the error that says:
Incorrect syntax near '='
Edit:
Statement where I did :
set #sql = 'declare ' + '#Temp'+ #colVar + ' int'
exec(#sql)
select #sql as 'SQLFORDECLARATIONS
outputs
declare #TempMiddleName int
yet when I try to set value in the variable gives error that it should be declared first.
The set statement results in :
select #TempMiddleName=dbo.[MatchMiddleName](MiddleNameFromUser,MiddleNameFromTable,0)
which is what is should be yet it not able to see the declared variable
The stored procedure is as follows:
create procedure SearchProcedure
(
#firstname nvarchar(20),
#middlename nvarchar(20) = null,
#lastname nvarchar(20),
#DOB Date = null,
#SSN nvarchar(30)= null,
#ZIP nvarchar(10)= null,
#StateOfResidence nvarchar(2)= null,
#City nvarchar(20)= null,
#StreetName nvarchar(20)= null,
#StreetType nvarchar(20)= null,
#BuildingNumber int= null,
#Aptnumber nvarchar(10)= null
)
As
DECLARE #sSQL NVARCHAR(2000), #Where NVARCHAR(1000) = ' '
declare #Percent int,
#FN nvarchar(20),
#MN nvarchar(20) = null,
#LN nvarchar(20),
#DateOfB Date = null,
#SSNumber nvarchar(30)= null,
#ZIPCode nvarchar(10)= null,
#StateOfRes nvarchar(2)= null,
#CityOfRes nvarchar(20)= null,
#StreetNameRes nvarchar(20)= null,
#StreetTypeRes nvarchar(20)= null,
#BuildingNumberRes int= null,
#AptnumberRes nvarchar(10)= null
set #Percent = 0
create table #results
(
firstname nvarchar(20) not null,
middlename nvarchar(20),
lastname nvarchar(20)not null,
PercentageMatch int not null,
DOB Date,
SSN nvarchar(30),
ZIP nvarchar(10),
[State] nvarchar(2),
City nvarchar(20),
StreetName nvarchar(20),
StreetType nvarchar(20),
BuildingNumber int,
Aptnumber nvarchar(10)
)
declare c Cursor local static Read_only
for
SELECT * from dbo.Patients where firstname = #firstname
open c
fetch next from c into #FN,
#MN,
#LN,
#DateOfB,
#SSNumber,
#ZIPCode,
#StateOfRes,
#CityOfRes,
#StreetNameRes,
#StreetTypeRes,
#BuildingNumberRes,
#AptnumberRes
while ##FETCH_STATUS = 0 BEGIN
/*set #Percent = dbo.[MatchLastName](#lastname, #LN, #Percent)
set #Percent = dbo.[MatchMiddleName](#middlename, #MN, #Percent)
set #Percent = dbo.[MatchCity](#City, #CityOfRes, #Percent)*/
Exec [dbo].[OutputProcedure] #lastname, #LN, #middlename, #MN,#City, #CityOfRes, #Percent output
Insert into #results values
(#FN,#MN,#LN,#Percent, #DateOfB,#SSNumber, #ZIPCode,#StateOfRes,#CityOfRes,#StreetNameRes,#StreetTypeRes,#BuildingNumberRes,#AptnumberRes)
fetch next from c into #FN,
#MN,
#LN,
#DateOfB,
#SSNumber,
#ZIPCode,
#StateOfRes,
#CityOfRes,
#StreetNameRes,
#StreetTypeRes,
#BuildingNumberRes,
#AptnumberRes
end
select * from #results order by PercentageMatch desc
IF OBJECT_ID('tempdb..#results') IS NOT NULL DROP TABLE #results
go
OutputProcedure code is as follows:
CREATE Procedure OutputProcedure
(
#LastNameFromUser nvarchar(20) = null,
#LastNameFromTable nvarchar(20),
#MiddleNameFromUser nvarchar(20) = null,
#MiddleNameFromTable nvarchar(20) = null,
#CityFromUser nvarchar(20) = null,
#CityFromTable nvarchar(20) = null,
#Percentage int out
)
AS
BEGIN
select 'OUTPUTPROCEDURECALLED'
declare #maxvalue int
DECLARE #variableTable TABLE (
idx int identity(1,1),
matchvalue nvarchar(15))
INSERT INTO #variableTable(matchvalue) values ('MiddleName')
INSERT INTO #variableTable(matchvalue) values ('LastName')
INSERT INTO #variableTable(matchvalue) values ('City')
SELECT * FROM #variableTable
DECLARE #counter int
declare #sql nvarchar(100)
declare #sql2 nvarchar(25), #finalResult nvarchar(100)
declare #sql3 nvarchar(300), #sql4 nvarchar(15), #tempresultStore nvarchar(20), #temp int, #temp2 int, #average int
SET #counter = 1
SELECT #maxvalue = (SELECT MAX(idx) FROM #variableTable)
select #maxvalue as 'MAXVALUE'
WHILE(#counter <= #maxvalue)
BEGIN
DECLARE #colVar nvarchar(15)
SELECT #colVar = matchvalue FROM #variableTable WHERE idx = #counter
set #sql = 'declare ' + '#Temp'+ #colVar + ' int'
exec(#sql)
select #sql as 'SQLFORDECLARATIONS'
/*set #temp = CHARINDEX(' ',#sql)
select #temp as 'resultofcharindex'
set #temp2 = LEN(#sql) - (#temp)
SELECT #temp2 AS 'AFTERADDING1'
set #tempresultStore = right(#sql, #temp2)*/
set #tempresultStore = 'Temp'+#colVar
SELECT #tempresultStore AS 'FINALCUTPART'
set #sql3 = 'set ' + ' ' + #tempresultStore + '=' + 'dbo.[Match' + #colVar + '](' + #colVar + 'FromUser' + ',' + #colVar + 'FromTable' + ',' + '0)'
EXEC(#sql3)
select #sql3 as 'check sql query formed'
set #finalResult = #finalResult + #tempresultStore
select #finalResult as 'SUM'
SET #counter = #counter + 1
select #counter as 'COUNTERVALUE'
END
set #Percentage = #finalResult/#maxvalue
SELECT #Percentage AS 'FINALRESULT'
RETURN
END
--Setting variable in Dynamic SQL
DECLARE
#sql NVARCHAR(MAX),
#Name NVARCHAR(100)
SET #Name = '#B2E0EB1A'
SET #sql =
'
DECLARE #MyVar NVARCHAR(100)
SELECT TOP 1 #MyVar = name FROM sys.objects WHERE name LIKE ''%a''--Escaping single quote with double quote
PRINT #MyVar
'
EXEC(#sql)
SET #sql =
'
DECLARE #MyVar NVARCHAR(100)
SET #MyVar = '''+(SELECT TOP 1 name FROM sys.objects WHERE name LIKE '%a')+'''--Escaping single quote with double quote
PRINT #MyVar
'
EXEC(#sql)
SET #sql =
'
DECLARE #MyVar NVARCHAR(100)
SET #MyVar = '''+#Name+'''--Escaping single quote with double quote
PRINT #MyVar
'
EXEC(#sql)
SET #sql =
'
DECLARE #MyVar NVARCHAR(100)
SET #MyVar = ''#B2E0EB1A''--Escaping single quote with double quote
PRINT #MyVar
'
EXEC(#sql)
If you want to get output variable from your dynamic query you have to use sp_executesql procedure instead of EXEC()
Study this code
DECLARE #DynamicSQLOutput NVARCHAR(100)
DECLARE #SQL nvarchar(500);
DECLARE #ParmeterDefinition nvarchar(500);
--in this variabe you write the variables which you want to be declared in the dynamic sql without using the declare
SET #ParmeterDefinition = N'#FinalOutputResultInDynamicSQL NVARCHAR(100) OUTPUT';
--here you write your dynamic code
SELECT #SQL = N'SET #FinalOutputResultInDynamicSQL = ''test'' '
EXEC sp_executesql
#SQL, --Execute code
#ParmeterDefinition, -- Define Parameters
#FinalOutputResultInDynamicSQL = #DynamicSQLOutput OUTPUT --Get output
--Note that #FinalOutputResultInDynamicSQL is only defined in #ParmeterDefinition but not outside of the dynamic sql
PRINT #DynamicSQLOutput;
I think too many things wrong in your Dynamic sql. I found one
SET #sql3 = 'set ' + ' ' + #tempresultStore + ' = ' + 'dbo.[Match'
+ #colVar + '](' + #colVar + 'FromUser' + ',' + #colVar
+ 'FromTable' + ',' + '0)'
In the above code instead of Set use Select. Looks like you are selecting from a UDF. Try this
SET #sql3 = 'Select ' + ' ' + #tempresultStore + ' = ' + 'dbo.[Match'
+ #colVar + '](' + #colVar + 'FromUser' + ',' + #colVar
+ 'FromTable' + ',' + '0)'
Note : To debug Dynamic Sql before Exec #sql just use print #sql to check the syntax and other stuff in generated sql
I can't find any error and can run the exec without anerror message.
Edit: After I created the (now avialbe) output procedure and uncomment its call, I'm getting the error too...
Still investigating
Edit2:
In the Output procedure you have to use
set #sql = 'declare ' + '#Temp'+ #colVar + ' int' (# before Temp) and
set #sql3 = 'set ' + ' #' + #tempresultStore" (additional # after the 'set'.
Btw: you can exec more than one statement in Dynamic SQL so you could use f.e. exec (#sql + '; ' + #sql3);

Asynchronous Procedure Execution with Parameters

I have been dealing with a similar issue to the one posed in this question - except in my context I am performing the command from an ASP.NET webpage.
Remus Rusanu posted an excellent solution using Service Broker Activation on his personal website, which I was able to get working great.
However I have had no luck getting his example which accepts parameters to function. It is supposed to insert data into the withParam table.
exec usp_AsyncExecInvoke #procedureName = N'usp_withParam'
, #p1 = 1.0, #n1 = N'#id'
, #p2 = N'Foo', #n2='#name'
, #p3 = 0xBAADF00D, #n3 = '#bytes'
, #token = #token output;
waitfor delay '00:00:05';
select * from AsyncExecResults;
select * from withParam;
instead it completes without error and SELECT * withParam shows an empty table.
The SELECT * AsyncExecResults table shows the command was submitted but doesn't display any error information (as it should if there was an error).
Passing Parameters to a Background Procedure
It has been suggested in the comments of the webpage that there is an issue using quotename if you use a schema it ends up wrapping it like this [MySchema.SomeFunction]
Removing quotename has not made a difference.
select #stmt = #stmtDeclarations + #stmtValues + N'
exec ' + #x.value(N'(//procedure/name)[1]', N'sysname');
As the query is executing without error I have very little to go on to debug this further. Does anyone know what else might cause this effect?
The Code
create table [AsyncExecResults] (
[token] uniqueidentifier primary key
, [submit_time] datetime not null
, [start_time] datetime null
, [finish_time] datetime null
, [error_number] int null
, [error_message] nvarchar(2048) null);
go
create queue [AsyncExecQueue];
go
create service [AsyncExecService] on queue [AsyncExecQueue] ([DEFAULT]);
GO
-- Dynamic SQL helper procedure
-- Extracts the parameters from the message body
-- Creates the invocation Transact-SQL batch
-- Invokes the dynmic SQL batch
create procedure [usp_procedureInvokeHelper] (#x xml)
as
begin
set nocount on;
declare #stmt nvarchar(max)
, #stmtDeclarations nvarchar(max)
, #stmtValues nvarchar(max)
, #i int
, #countParams int
, #namedParams nvarchar(max)
, #paramName sysname
, #paramType sysname
, #paramPrecision int
, #paramScale int
, #paramLength int
, #paramTypeFull nvarchar(300)
, #comma nchar(1)
select #i = 0
, #stmtDeclarations = N''
, #stmtValues = N''
, #namedParams = N''
, #comma = N''
declare crsParam cursor forward_only static read_only for
select x.value(N'#Name', N'sysname')
, x.value(N'#BaseType', N'sysname')
, x.value(N'#Precision', N'int')
, x.value(N'#Scale', N'int')
, x.value(N'#MaxLength', N'int')
from #x.nodes(N'//procedure/parameters/parameter') t(x);
open crsParam;
fetch next from crsParam into #paramName
, #paramType
, #paramPrecision
, #paramScale
, #paramLength;
while (##fetch_status = 0)
begin
select #i = #i + 1;
select #paramTypeFull = #paramType +
case
when #paramType in (N'varchar'
, N'nvarchar'
, N'varbinary'
, N'char'
, N'nchar'
, N'binary') then
N'(' + cast(#paramLength as nvarchar(5)) + N')'
when #paramType in (N'numeric') then
N'(' + cast(#paramPrecision as nvarchar(10)) + N',' +
cast(#paramScale as nvarchar(10))+ N')'
else N''
end;
-- Some basic sanity check on the input XML
if (#paramName is NULL
or #paramType is NULL
or #paramTypeFull is NULL
or charindex(N'''', #paramName) > 0
or charindex(N'''', #paramTypeFull) > 0)
raiserror(N'Incorrect parameter attributes %i: %s:%s %i:%i:%i'
, 16, 10, #i, #paramName, #paramType
, #paramPrecision, #paramScale, #paramLength);
select #stmtDeclarations = #stmtDeclarations + N'
declare #pt' + cast(#i as varchar(3)) + N' ' + #paramTypeFull
, #stmtValues = #stmtValues + N'
select #pt' + cast(#i as varchar(3)) + N'=#x.value(
N''(//procedure/parameters/parameter)[' + cast(#i as varchar(3))
+ N']'', N''' + #paramTypeFull + ''');'
, #namedParams = #namedParams + #comma + #paramName
+ N'=#pt' + cast(#i as varchar(3));
select #comma = N',';
fetch next from crsParam into #paramName
, #paramType
, #paramPrecision
, #paramScale
, #paramLength;
end
close crsParam;
deallocate crsParam;
select #stmt = #stmtDeclarations + #stmtValues + N'
exec ' + quotename(#x.value(N'(//procedure/name)[1]', N'sysname'));
if (#namedParams != N'')
select #stmt = #stmt + N' ' + #namedParams;
exec sp_executesql #stmt, N'#x xml', #x;
end
go
create procedure usp_AsyncExecActivated
as
begin
set nocount on;
declare #h uniqueidentifier
, #messageTypeName sysname
, #messageBody varbinary(max)
, #xmlBody xml
, #startTime datetime
, #finishTime datetime
, #execErrorNumber int
, #execErrorMessage nvarchar(2048)
, #xactState smallint
, #token uniqueidentifier;
begin transaction;
begin try;
receive top(1)
#h = [conversation_handle]
, #messageTypeName = [message_type_name]
, #messageBody = [message_body]
from [AsyncExecQueue];
if (#h is not null)
begin
if (#messageTypeName = N'DEFAULT')
begin
-- The DEFAULT message type is a procedure invocation.
--
select #xmlBody = CAST(#messageBody as xml);
save transaction usp_AsyncExec_procedure;
select #startTime = GETUTCDATE();
begin try
exec [usp_procedureInvokeHelper] #xmlBody;
end try
begin catch
-- This catch block tries to deal with failures of the procedure execution
-- If possible it rolls back to the savepoint created earlier, allowing
-- the activated procedure to continue. If the executed procedure
-- raises an error with severity 16 or higher, it will doom the transaction
-- and thus rollback the RECEIVE. Such case will be a poison message,
-- resulting in the queue disabling.
--
select #execErrorNumber = ERROR_NUMBER(),
#execErrorMessage = ERROR_MESSAGE(),
#xactState = XACT_STATE();
if (#xactState = -1)
begin
rollback;
raiserror(N'Unrecoverable error in procedure: %i: %s', 16, 10,
#execErrorNumber, #execErrorMessage);
end
else if (#xactState = 1)
begin
rollback transaction usp_AsyncExec_procedure;
end
end catch
select #finishTime = GETUTCDATE();
select #token = [conversation_id]
from sys.conversation_endpoints
where [conversation_handle] = #h;
if (#token is null)
begin
raiserror(N'Internal consistency error: conversation not found', 16, 20);
end
update [AsyncExecResults] set
[start_time] = #starttime
, [finish_time] = #finishTime
, [error_number] = #execErrorNumber
, [error_message] = #execErrorMessage
where [token] = #token;
if (0 = ##ROWCOUNT)
begin
raiserror(N'Internal consistency error: token not found', 16, 30);
end
end conversation #h;
end
else if (#messageTypeName = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog')
begin
end conversation #h;
end
else if (#messageTypeName = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error')
begin
declare #errorNumber int
, #errorMessage nvarchar(4000);
select #xmlBody = CAST(#messageBody as xml);
with xmlnamespaces (DEFAULT N'http://schemas.microsoft.com/SQL/ServiceBroker/Error')
select #errorNumber = #xmlBody.value ('(/Error/Code)[1]', 'INT'),
#errorMessage = #xmlBody.value ('(/Error/Description)[1]', 'NVARCHAR(4000)');
-- Update the request with the received error
select #token = [conversation_id]
from sys.conversation_endpoints
where [conversation_handle] = #h;
update [AsyncExecResults] set
[error_number] = #errorNumber
, [error_message] = #errorMessage
where [token] = #token;
end conversation #h;
end
else
begin
raiserror(N'Received unexpected message type: %s', 16, 50, #messageTypeName);
end
end
commit;
end try
begin catch
declare #error int
, #message nvarchar(2048);
select #error = ERROR_NUMBER()
, #message = ERROR_MESSAGE()
, #xactState = XACT_STATE();
if (#xactState <> 0)
begin
rollback;
end;
raiserror(N'Error: %i, %s', 1, 60, #error, #message) with log;
end catch
end
go
alter queue [AsyncExecQueue]
with activation (
procedure_name = [usp_AsyncExecActivated]
, max_queue_readers = 1
, execute as owner
, status = on);
go
-- Helper function to create the XML element
-- for a passed in parameter
create function [dbo].[fn_DescribeSqlVariant] (
#p sql_variant
, #n sysname)
returns xml
with schemabinding
as
begin
return (
select #n as [#Name]
, sql_variant_property(#p, 'BaseType') as [#BaseType]
, sql_variant_property(#p, 'Precision') as [#Precision]
, sql_variant_property(#p, 'Scale') as [#Scale]
, sql_variant_property(#p, 'MaxLength') as [#MaxLength]
, #p
for xml path('parameter'), type)
end
GO
-- Invocation wrapper. Accepts arbitrary
-- named parameetrs to be passed to the
-- background procedure
create procedure [usp_AsyncExecInvoke]
#procedureName sysname
, #p1 sql_variant = NULL, #n1 sysname = NULL
, #p2 sql_variant = NULL, #n2 sysname = NULL
, #p3 sql_variant = NULL, #n3 sysname = NULL
, #p4 sql_variant = NULL, #n4 sysname = NULL
, #p5 sql_variant = NULL, #n5 sysname = NULL
, #token uniqueidentifier output
as
begin
declare #h uniqueidentifier
, #xmlBody xml
, #trancount int;
set nocount on;
set #trancount = ##trancount;
if #trancount = 0
begin transaction
else
save transaction usp_AsyncExecInvoke;
begin try
begin dialog conversation #h
from service [AsyncExecService]
to service N'AsyncExecService', 'current database'
with encryption = off;
select #token = [conversation_id]
from sys.conversation_endpoints
where [conversation_handle] = #h;
select #xmlBody = (
select #procedureName as [name]
, (select * from (
select [dbo].[fn_DescribeSqlVariant] (#p1, #n1) AS [*]
WHERE #p1 IS NOT NULL
union all select [dbo].[fn_DescribeSqlVariant] (#p2, #n2) AS [*]
WHERE #p2 IS NOT NULL
union all select [dbo].[fn_DescribeSqlVariant] (#p3, #n3) AS [*]
WHERE #p3 IS NOT NULL
union all select [dbo].[fn_DescribeSqlVariant] (#p4, #n4) AS [*]
WHERE #p4 IS NOT NULL
union all select [dbo].[fn_DescribeSqlVariant] (#p5, #n5) AS [*]
WHERE #p5 IS NOT NULL
) as p for xml path(''), type
) as [parameters]
for xml path('procedure'), type);
send on conversation #h (#xmlBody);
insert into [AsyncExecResults]
([token], [submit_time])
values
(#token, getutcdate());
if #trancount = 0
commit;
end try
begin catch
declare #error int
, #message nvarchar(2048)
, #xactState smallint;
select #error = ERROR_NUMBER()
, #message = ERROR_MESSAGE()
, #xactState = XACT_STATE();
if #xactState = -1
rollback;
if #xactState = 1 and #trancount = 0
rollback
if #xactState = 1 and #trancount > 0
rollback transaction usp_my_procedure_name;
raiserror(N'Error: %i, %s', 16, 1, #error, #message);
end catch
end
go
-- Sample invocation example
-- The usp_withParam will insert
-- all the received parameters into this table
--
create table [withParam] (
id numeric(4,1) NULL
, name varchar(150) NULL
, date datetime NULL
, value int NULL
, bytes varbinary(max) NULL);
go
create procedure usp_withParam
#id numeric(4,1)
, #name varchar(150)
, #date datetime = NULL
, #value int = 0
, #bytes varbinary(max) = NULL
as
begin
insert into [withParam] (
id
, name
, date
, value
, bytes)
select #id as [id]
, #name as [name]
, #date as [date]
, #value as [value]
, #bytes as [bytes]
end
go
declare #token uniqueidentifier;
exec usp_AsyncExecInvoke #procedureName = N'usp_withParam'
, #p1 = 1.0, #n1 = N'#id'
, #p2 = N'Foo', #n2='#name'
, #p3 = 0xBAADF00D, #n3 = '#bytes'
, #token = #token output;
waitfor delay '00:00:05';
select * from AsyncExecResults;
select * from withParam;
go
It does appear that Remus's blog post neglected to note that we need to use SET ENABLE_BROKER to make the async tasks actually run.
This worked for me (only run this if you are OK with all connections to your DB being closed, this command is from SET ENABLE_BROKER never completes in SQL Server):
ALTER DATABASE [Database_name] SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE;
After running the command above I ran this and was happy to see that the "start_time", "finish_time" and if there were errors the "error_message" columns are now populated!
SELECT * FROM [dbo].[AsyncExecResults]
Edit: See also, this file for the complete code (which the author posted from his blog post) which worked for me once I used the "SET ENABLE_BROKER" command above): https://github.com/rusanu/async_tsql/blob/master/src/with_params.sql

Having issues with UPDATE command

Using this SP I keep getting an error on the UPDATE statement indicating that I have conversion problem or something. But ID is an integer in all of my tables....
Conversion failed when converting the varchar value 'UPDATE tblLangenUS SET [lang_String] = ' - asdfgsdfg', [prev_LangString] = ' ', [needsTranslation] = 'false' WHERE [ID] = '' to data type int.
#currTable varchar(100),
#ID int,
#short_Text varchar(250),
#brief_Descrip varchar(250) = Null,
#needsTranslation varchar(10) = Null,
#prev_LangString varchar(250) = Null,
#lang_String varchar(250) = Null,
#original_lang_String varchar(250) = Null,
#StringID_from_Master varchar(250),
#GUID varchar(250) = Null
/*
*/
AS
SET NOCOUNT ON;
DECLARE #userTable AS VARCHAR(200);
SET #userTable = #currTable
DECLARE #submitDate1 DATETIME;
SET #submitDate1 = GETDATE()
SET #prev_LangString = #original_lang_String
SET #needsTranslation = 'false'
DECLARE #sql varchar(max)
-- Establish update to the language tabel of user and prepare to search DB for all strings that will need to be updated.
BEGIN
SET #sql = 'UPDATE ' + #currTable + ' SET [lang_String] = ''' + #lang_String + ''', [prev_LangString] = ''' + #prev_LangString + ''', [needsTranslation] = ''' + #needsTranslation + ''' WHERE [ID] = ''' + #ID + '''; '
EXEC #sql
#sql = ''
END
BEGIN
DECLARE usedIN_DBScursor CURSOR
FOR
SELECT tblUniquetblStringsMaster_ID, Database_Name, dbKeyID_ofStringName
FROM tblDBUsage
WHERE (tblUniquetblStringsMaster_ID = #StringID_from_Master );
-- Declare the variables to store the values returned by FETCH.
DECLARE #tblUniquetblStringsMaster_ID AS INT;
DECLARE #dbKEYID as INT;
DECLARE #dbName as varchar(100);
OPEN usedIN_DBScursor;
-- Perform the first fetch and store the values in variables.
-- Note: The variables are in the same order as the columns
-- in the SELECT statement.
FETCH NEXT FROM usedIN_DBScursor
INTO #tblUniquetblStringsMaster_ID, #dbName, #dbKEYID;
-- Check ##FETCH_STATUS to see if there are any more rows to fetch.
WHILE ##FETCH_STATUS = 0
BEGIN
-- Update pending strings table with translation.
BEGIN
INSERT INTO tblPendingDBUpdates
(stringMasterID, databaseName, databaseStringID, englishText, foreignLangText, submitDate, GUID)
VALUES (#StringID_from_Master, #dbName, #dbKEYID, #short_Text, #lang_String, #submitDate1, #GUID);
END
-- SET #sql = ''
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM usedIN_DBScursor
INTO #tblUniquetblStringsMaster_ID, #dbName, #dbKEYID;
END
CLOSE usedIN_DBScursor;
DEALLOCATE usedIN_DBScursor;
END
RETURN
If the ID is an int, you must CAST it to an nvarchar
SET #sql = 'UPDATE ' + #currTable + ' SET [lang_String] = ''' + #lang_String + ''', [prev_LangString] = ''' + #prev_LangString + ''', [needsTranslation] = ''' + #needsTranslation + ''' WHERE [ID] = ''' + CAST(#ID as nvarchar(10)) + '''; '
Otherwise, you are trying to add a string and an integer together, which won't work.
Notice this part:
' WHERE [ID] = ''' + CAST(#ID as nvarchar(10)) + '''
I think you must also change your EXEC syntax to:
EXEC(#sql)