best approach to execute a dynamic query inside a SP - sql

I'm having some trouble executing a dynamic query inside my SP, and I thought asking for some help as I can't execute it correctly no matter what I try:
I have tried:
SET #subWorksQuery =
'UPDATE JK_SubscriberWorks SET ' +
'update_date = convert(datetime, ''' + #dateNow + ''', 103), ' +
'challenge_' + convert(nvarchar(2), #challengeDay) + '_q = ''' + #challengeQuestion + ''', ' +
'challenge_' + convert(nvarchar(2), #challengeDay) + '_a = ''' + #challengeAnswer + ''' ' +
'WHERE subscriberwork_id = '' + convert(nvarchar(10), #subscriberWorksId) + '';';
execute #execReturn = #subWorksQuery
but I always get:
Msg 203, Level 16, State 2, Procedure sp_InsertChallengeResponse_test,
Line 112
The name 'UPDATE JK_SubscriberWorks SET update_date = convert(datetime, '23-12-2011 23:35:17', 103), challenge_23_q =
'Hvilket år blev Klasselotteriet omdannet til et aktieselskab? Få hjælp til svaret.',
challenge_23_a = '1992' WHERE subscriberwork_id = ' +
convert(nvarchar(10), #subscriberWorksId) + ';' is not a valid
identifier.
Removing the UPDATE statement from that error and run it independently, it runs and performs the update
If I use sp_executesql like
SET #subWorksQuery =
N'UPDATE JK_SubscriberWorks SET ' +
'update_date = #a, ' +
'challenge_' + convert(nvarchar(2), #challengeDay) + '_q = #b, ' +
'challenge_' + convert(nvarchar(2), #challengeDay) + '_a = #c ' +
'WHERE subscriberwork_id = #d;';
SET #parmDefinition = N'#a datetime, #b nvarchar(250), #c nvarchar(500), #d decimal';
execute sp_executesql
#subWorksQuery,
#parmDefinition,
#a = #CreateDate, #b = #challengeQuestion, #c = #challengeAnswer, #d = #subscriberWorksId;
It never performs the UPDATE, but does not throw any error.
What am I missing here?

Run it like this:
execute (#subWorksQuery)
[you won't be getting anything back from the update statement in the variable, and you can't run like this execute (#execReturn = #subWorksQuery) ]
Without parentheses it seems to be starting parsing, assuming it is a stored procedure name, but failing when it hits the max length for one.
In saying that, it is better to use sp_executesql with parameters.

I am not sure what you are looking for in the return value, but if you just need the count of rows affected, that should be easy to obtain.
Change:
execute #execReturn = #subWorksQuery
to:
execute (#subWorksQuery)
select #execReturn = ##ROWCOUNT

just a thought...your #d parameter is a decimal value. Is your id an int? is there a possible data type conflict?
how are your sp input parameters defined? Could you post the full sp?
Dave

Related

How to update table with while loop in Stored Procedure?

I want to update my dynamic table in while loop.
Here is my code:
While (#j<=#tmp_getRowCount)
Begin
Set #firstcolumn = (Select SplitFirst_tblAR from #result_AR Where rownumber = #j) //String//
Set #secondcolumn = (Select EMail_tblAR from #result_AR Where rownumber = #j) //String//
Set #thirdcolumn = (Select SplitFirst_tblKul from #result_AR Where rownumber = #j) //String//
Set #fourthcolumn = (Select EMail_tblKul from #result_AR Where rownumber = #j) //String//
insert into #test Values(#tmp_ID, #firstcolumn,#secondcolumn,#thirdcolumn,#fourthcolumn)
if ((#firstcolumn = #thirdcolumn) AND (#secondcolumn != #fourthcolumn) AND (#firstcolumn != ''))
begin
Set #q_updateTable = 'Update '+ quotename(#tablename) +' Set '+#columnname+' = ''' + #fourthcolumn + ''' Where ID = ' + #tmp_ID + ''
Exec sp_executesql #q_updateTable
end
SET #j = #j+1
End
My result_AR table:
I know the error is in here:
Where ID = ' + #tmp_ID + ''
When I change this Where clause as,
Where '+#columnname+' = ''' + #secondcolumn + ''' '
code works correctly.
Why can't I set as ID my where clause? I am getting ID value as integer.
The error is 'Query completed with errors'.
Thanks in advance.
you can not set Id in where clause because the id is integer value and you are concatenating it with string (varchar).
So first you have to convert it in (String)varchar and the you can use it where clause.
Like :
Set #q_updateTable = 'Update '+ quotename(#tablename) +' Set '+#columnname+' = ''' + #fourthcolumn + ''' Where ID = ' + convert(varchar,#tmp_ID) + ''
Exec sp_executesql #q_updateTable
you have to use "convert(varchar,#tmp_ID)" insted of "#tmp_ID"

Dynamic sql is giving syntax error.

I am executing the following sql. I get a syntax error which is (Incorrect syntax near '=')
The query executes fine and gives proper results when executed normally. couldn't understand. plz take a look.
DECLARE #pvchMachineId VARCHAR(100) = ''
DECLARE #pvchMake VARCHAR(100) = ''
DECLARE #sql NVARCHAR(1000)
SELECT #sql = ' SELECT TOP 20 x.intId, x.vchMachineId, x.AUDenom, x.intGroupId,
x.vchMake, x.vchModel, x.mCurrency
from dbo.Machine x
inner join
(select max(m1.AUDenom) as audenom, m1.vchMachineId
from dbo.Machine m1
left JOIN dbo.ImportedFile ife on m1.intImportedFileId = ife.intId
WHERE ife.dtFileDate >= ''1-1-2013'' AND ife.dtFileDate <= ''1-29-2014'' AND
--following two lines cause the error
(' + #pvchMake + '= ''0'' OR m1.vchMake = #pvchMake) AND
(' + #pvchMachineId +'= ''0'' OR m1.vchMachineId = #pvchMachineId)
group by vchMachineId) y
on x.AUDenom = y.audenom and x.vchMachineId = y.vchMachineId
ORDER BY x.AUDenom DESC'
Update your query to the following
(#pvchMake = ''0'' OR m1.vchMake = #pvchMake) AND
(#pvchMachineId = ''0'' OR m1.vchMachineId = #pvchMachineId)
than later when you go to execute just pass it in as parameters to sp_executesql function.
EXEC sp_executesql #sql
,N'#pvchMachineId VARCHAR(100), #pvchMake VARCHAR(100)'
,#pvchMachineId,#pvchMake
or this which is cleaner
Declare #ParametersDefinition NVARCHAR(max) = N'#pvchMachineId VARCHAR(100), #pvchMake VARCHAR(100)'
EXEC sp_executesql #sql, #ParametersDefinition, #pvchMachineId,#pvchMake
In the end you do not want to concatenate your dynamic SQL statement, it opens it up for SQL Injections. Even though it is a valid option it should be avoided at all cost.
This statement :
'(' + #pvchMake + '= ''0'' OR m1.vchMake = #pvchMake)'
Will output, since the variables are not initialized by anything else than '' :
(= '0' OR m1.vchMake = #pvchMake)
Which is not correct syntaxically.
You should use :
'(''' + #pvchMake + '''= ''0'' OR m1.vchMake = #pvchMake)'
Which would output :
(''= '0' OR m1.vchMake = #pvchMake)
Maybe this can make sense:
...
(''' + #pvchMake + '''= ''0'' OR m1.vchMake = ''' + #pvchMake +''') AND
(''' + #pvchMachineId +'''= ''0'' OR m1.vchMachineId = ''' + #pvchMachineId + ''')
...

Date conversion error on UPDATE command

I have a stored procedure that is throwing an error on an UPDATE command here are the pertinent lines of code.
DECLARE #submitDate1 DATETIME;
SET #submitDate1 = GETDATE()
SET #sql = 'UPDATE ' + #currTable + ' SET [lang_String] = ''' + #lang_String + ''', [date_Changed] = ''' + #submitDate1 + ''', [prev_LangString] = ''' + #prev_LangString + ''', [needsTranslation] = ''' + #needsTranslation + ''' WHERE [ID] = ' + CAST(#ID as nvarchar(10)) + '; '
EXEC(#sql)
Here is the error...
Conversion failed when converting date and/or time from character string.
You have to convert the date into a string before concatenating it to the other strings:
... = ''' + convert(varchar(20), #submitDate1) + ''', [...
use
convert(varchar,#submitDate1)
at the place where you have used #submitDate1 variable.
SQL does not do implicit conversion from date to string!

Writing a dreaded SQL search query (2nd phase)

I am working on a search query (with an asp.net 3.5 front end) which seems quite simple, but is quite complex.
The complete query is:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[usp_Item_Search]
#Item_Num varchar(30) = NULL
,#Search_Type int = NULL
,#Vendor_Num varchar(10) = NULL
,#Search_User_ID int = 0
,#StartDate smalldatetime = NULL
,#EndDate smalldatetime = NULL
AS
DECLARE #SQLstr as nvarchar(4000)
Set #SQLstr = 'SELECT RecID, Vendor_Num, Vendor_Name, InvoiceNum, Item_Num,
(SELECT CONVERT(VARCHAR(11), RecDate, 106) AS [DD MON YYYY]) As RecDate, NeedsUpdate, RecAddUserID FROM [tbl_ItemLog] where 1=1 '
IF (#Item_Num IS NOT NULL and LTRIM(#Item_Num) <> '')
Begin
If #Search_Type = 0
BEGIN
Set #SQLstr = #SQLstr + 'AND Item_Num LIKE ''' + #Item_Num + '%'''
END
If #Search_Type = 1
BEGIN
Set #SQLstr = #SQLstr + 'AND Item_Num LIKE ''%' + #Item_Num + '%'''
END
If #Search_Type = 2
BEGIN
Set #SQLstr = #SQLstr + 'AND Item_Num LIKE ''%' + #Item_Num + ''''
END
End
IF (#Vendor_Num IS NOT NULL and LTRIM(#Vendor_Num) <> '')
Begin
Set #SQLstr = #SQLstr + ' AND Vendor_Num = ''' + #Vendor_Num + ''''
End
IF (#Search_User_ID IS NOT NULL and #Search_User_ID > 0)
Begin
Set #SQLstr = #SQLstr + ' AND RecAddUserID = ' + convert(nvarchar(20),#Search_User_ID)
End
Set #SQLstr = #SQLstr + ' AND (RecDate BETWEEN ''' + convert(nvarchar(10),#StartDate,106) + ''' AND ''' + convert(nvarchar(10),#EndDate,106) + ''')'
PRINT (#SQLstr)
--Execute (#SQLstr)
When I pass all empty parameter values, I get an error:
"Failed to convert parameter value
from a String to a Int32."
The asp.net code that is calling the stored proc is:
//Display search results in GridView;
SqlConnection con = new SqlConnection(strConn);
//string sqlItemSearch = "usp_Item_Search";
SqlCommand cmdItemSearch = new SqlCommand(sqlItemSearch, con);
cmdItemSearch.CommandType = CommandType.StoredProcedure;
cmdItemSearch.Parameters.Add(new SqlParameter("#Item_Num", SqlDbType.VarChar, 30));
cmdItemSearch.Parameters["#Item_Num"].Value = txtItemNumber.Text.Trim();
cmdItemSearch.Parameters.Add(new SqlParameter("#Search_Type", SqlDbType.Int));
cmdItemSearch.Parameters["#Search_Type"].Value = ddlSearchType.SelectedItem.Value;
cmdItemSearch.Parameters.Add(new SqlParameter("#Vendor_Num", SqlDbType.VarChar, 10));
cmdItemSearch.Parameters["#Vendor_Num"].Value = txtVendorNumber.Text.Trim();
cmdItemSearch.Parameters.Add(new SqlParameter("#Search_User_ID", SqlDbType.Int));
cmdItemSearch.Parameters["#Search_User_ID"].Value = ddlSeachUser.SelectedItem.Value;
if (!string.IsNullOrEmpty(txtStartDate.Text))
{
cmdItemSearch.Parameters.Add(new SqlParameter("#StartDate", SqlDbType.DateTime));
cmdItemSearch.Parameters["#StartDate"].Value = Convert.ToDateTime(txtStartDate.Text.Trim());
}
else
{
cmdItemSearch.Parameters.Add(new SqlParameter("#StartDate", SqlDbType.DateTime));
cmdItemSearch.Parameters["#StartDate"].Value = Convert.ToDateTime("01/01/1996");
}
if (!string.IsNullOrEmpty(txtEndDate.Text))
{
cmdItemSearch.Parameters.Add(new SqlParameter("#EndDate", SqlDbType.DateTime));
cmdItemSearch.Parameters["#EndDate"].Value = Convert.ToDateTime(txtEndDate.Text.Trim());
}
else
{
cmdItemSearch.Parameters.Add(new SqlParameter("#EndDate", SqlDbType.DateTime));
cmdItemSearch.Parameters["#EndDate"].Value = Convert.ToDateTime(DateTime.Now);
}
con.Open();
SqlDataAdapter ada = new SqlDataAdapter(cmdItemSearch);
DataSet ds = new DataSet();
ada.Fill(ds);
gvSearchDetailResults.DataSource = ds;
gvSearchDetailResults.DataBind();
pnlSearchResults.Visible = true;
How can I resolve this?
You're not quite building the string correctly as far as I can tell. If no #Item_Num is passed in, you'll end up with no WHERE key word... you'll just have "FROM [tblItem_Log] AND..."
I would make all of the criteria appends be "AND ..." and as your initial statement use:
FROM [tbl_Item_Log] WHERE (1=1)
Since you have code to return the generated string, why not put that into SSMS and try to run it?
I also just noticed that if you don't pass in date values that you will end up executing a NULL string, because your final concatenation will end up causing a NULL. These are the kinds of things that you need to pay very close attention to if you're going to be using dynamic SQL to build queries.
Once I corrected that I was able to run the stored procedure without any errors (at least to generate what looks like a valid SQL statement). That leads me to believe that it may be a problem with data types in the underlying table. Can you provide the definition for that?
One last note: Personally, I would use
CONVERT(VARCHAR(11), RecDate, 106) AS RecDate
instead of the seemingly unnecessary subquery that you have.
Yet another edit:
You may want to remove the code that checks LTRIM(#Search_User_ID) <> ''. It's a pointless bit of code and perhaps a setting particular to your server/connection is causing it to fail because of the type mismatch.
IF (Search_User_ID IS NOT NULL)
needs an # symbol infront of the variable
You say you are passing empty string in for all variables but one is an int, it can't take an empty string that is not int data. Can't believe I didn;t notice that the first time.
Why don't you use single parameterized query like this:
select
recdid,
Vendor_Num,
Vendor_Name,
InvoiceNum,
Item_Num,
CONVERT(VARCHAR(11), RecDate, 106) as RecDate,
NeedsUpdate,
RecAddUserID
FROM
[tbl_ItemLog] as t
where
(((Item_num like #Item_Num + '%' and #Search_Type = 0) OR
(Item_num like '%' + #Item_Num + '%' and #Search_Type = 1) OR
(Item_num like '%' + #Item_Num + '%' and #Search_Type = 2))
OR
#Item_Num IS NULL) AND
(Vendor_Num = #Vendor_Num OR #Vendor_Num IS NULL) AND
(RecAddUserId = #Search_User_Id OR #Search_User_Id IS NULL) AND
(RecDate BETWEEN #StartDate AND #EndDate)
You really have several different stored procedures here. Why not just write them separately? Everything that's controlled by switch statements could be easily in procedural code. Same for the LTRIM calls.
You could call them all from a single SP with switch statements; but I think it's generally better to not merge them in the first place. The SP queries will optimize more easily, and the code will be simpified. There's not much you gain by consolidating them.
Not sure of your business rules, but you could simplify this outside SQL with
switch(search_type) {
case 1:
do_query_type_1(args);
break;
case 2:
do_query_type_2(args);
break;
case 3:
do_query_type_3(args);
break;
default:
whatever ...
}
Also it looks like you have separate logic for cases where the item number is provided or not. Same for other fields. Each of your use cases looks like it resolves to a pretty simple query.

SQL Query within VS TableAdapter Query Configuration Wizard

I am trying to write an SQL query within Visual Studio TableAdapter Query Wizard
My SQL query is:
DECLARE #SQL varchar(255);
SET #SQL = ' SELECT * FROM dbAddress WHERE 1 = 1'
IF #ApexLine1 = ''
BEGIN
SET #SQL = #SQL + ' AND addLine1 IS NULL '
END
ELSE
BEGIN
SET #SQL = #SQL + ' AND addLine1 = ''' + #ApexLine1 + ''''
END
IF #ApexLine2 = ''
BEGIN
SET #SQL = #SQL + ' AND addLine2 IS NULL '
END
ELSE
BEGIN
SET #SQL = #SQL + ' AND addLine2 = ''' + #ApexLine2 + ''''
END
IF #ApexLine3 = ''
BEGIN
SET #SQL = #SQL + ' AND addLine3 IS NULL '
END
ELSE
BEGIN
SET #SQL = #SQL + ' AND addLine3 = ''' + #ApexLine3 + ''''
END
IF #ApexZip = ''
BEGIN
SET #SQL = #SQL + ' AND addPostCode IS NULL '
END
ELSE
BEGIN
SET #SQL = #SQL + ' AND addPostCode = ''' + #ApexZip + ''''
END
IF #ApexCity = ''
BEGIN
SET #SQL = #SQL + ' AND addLine4 IS NULL '
END
ELSE
BEGIN
SET #SQL = #SQL + ' AND addLine4 = ''' + #ApexCity + ''''
END
IF #ApexProv = ''
BEGIN
SET #SQL = #SQL + ' AND addLine5 IS NULL '
END
ELSE
BEGIN
SET #SQL = #SQL + ' AND addLine5 = ''' + #ApexProv + ''''
END
EXEC(#SQL)
I get the error:
'The Declare SQL contruct or statement is not supported'
If I remove the Declare statement I get error:
'The Set SQL construct or statement is not supported'
Is there a work around for this?
Thanks.
Anything like this:
SET #SQL = #SQL + ' AND addLine1 = ''' + #ApexLine1 + ''''
is EVIL. Don't do it. Variables like #ApexLine1 could contain anything, even something like this:
';DROP TABLE dbAddress--
Think very carefully about what would happen if someone entered something like that in your Address Line 1 field. The only correct solution here is to use the built-in sp_executesql stored procedure. Learn it, use it.
Aside from that, I think at least part of your problem might be that your #SQL variable is only 255 characters. It's easily possible your query is running out of space.