LIKE statement using parametrized SQL in vbscript - sql-server

I'm trying to create a LIKE SQL statement in vbscript using parametrized SQL.
The command text passed through is along the lines of
SET NOCOUNT ON;
DECLARE #pname as nvarchar(50);
SELECT #pname = ?;
SELECT *
FROM tblProject
WHERE projName LIKE #pname
And I'm concatenating % onto either side of the string that I'm passing through as pname. If I change the LIKE to an = and remove the %s then it works fine. And if I run the statement directly and replace #pname with '%searchterm%' it works fine. Any help would be much appreciated.
Edit: vbscript:
Set rsAnswers = Server.CreateObject("ADODB.Recordset")
Set cmd = server.createobject("ADODB.Command")
cmd.CommandText = mySQL
cmd.CommandType = 1
cmd.CommandTimeout = 900
cmd.ActiveConnection = svrPerformanceConnectionset prm = cmd.CreateParameter("#pname", 129, 1, 50, thisProjName)
cmd.Parameters.Append prm
rsAnswers.CursorLocation = 3
rsAnswers.Open cmd, , 0, 1
(thisProjName is getting a string from a form)
Thanks,
Tim

it is the expected behaviour because the parameter value is escaped to handle it as a value.
the solution is to move the concatenation of the % out of the parameter:
SET NOCOUNT ON;
SELECT *
FROM tblProject
WHERE projName LIKE '%' + #pname + '%';
notice the missing declaration & initialization of the parameter: inizialization and value assignement are performed by the VBScript engine and data access layer when creating the related objects in the script.

After trying many things, I found that the problem was the data type I was declaring my parameter as. I'm not sure why exactly but using adVarChar (200) rather than adChar (129) made the LIKE statement work.
Thanks to everybody who answered and commented!

Related

Is it possible to pass a NULL into an SQL Server Stored Procedure from Typescript

I'm stuck in a situation where i have to pass a value as Null to a uniqueidentifier variable i declared in a stored procedure.
The problem is that i have to pass an empty string to the variable, where it generates an error "Cannot convert varchar to uniqueidentifier". From eecuting the procedure in SQL serve, all works well, but typescript generates the above error...
Here is the procedure code executed:
USE [CMS_ONE]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[PrAdmissionReports]
#session = '82c16d40-56ba-4e5a-b6f4-8f3767fc48fa',
#campus = '0EF13205-3150-43F3-A37A-CDE57BFD544E',
#program = '929A0FCD-81C8-44D3-AC56-020E7C0AA2B2',
#fromDate = '2018-07-02',
#toDate = '2018-07-27'
SELECT 'Return Value' = #return_value
GO
I'm passing #program as ProgramDetailID = null to the procedure, but it keeps returning the error.
This is how i pass the values from the front:
this.sessionID +
"," +
this.campusID +
"," +
this.programDetailID +
"," +
this.fromDate +
"," +
this.toDate
Any help will be greatly appreciated
For sanity's sake I'm assuming you're using a javascript based backend here and not just calling directly into your database from the frontend because that would be dangerous.
You're concatenating an empty string there. you could use something like:
this.someField ? this.someField : 'NULL'
or
this.someField ?? 'NULL'
a better, safer way would be to parameterize your queries.

Stored procedure output parameters return empty

In my SQL Server 2014 I have a Stored procedure that returns 2 values in 2 variables as output:
#TotalNoRatio
#TotalRatio
Here are the results after execution:
#TotalNoRatio #TotalRatio
34510793 31857292
Return Value 0
Now I want those 2 values to be display in a Label on my form.
Here is the code:
cmd2.CommandType = CommandType.StoredProcedure
cmd2.Parameters.Add("#TotalNoRatio", SqlDbType.Decimal)
cmd2.Parameters.Add("#TotalRatio", SqlDbType.Decimal)
cmd2.ExecuteNonQuery()
Me.LTotal1.Text = cmd2.Parameters("#TotalNoRatio").Value
Me.LTotal2.Text = cmd2.Parameters("#TotalRatio").Value
Everything runs fine without errors except that the results are empty.
You need to define direction as return something like this:
SqlParameter retval = sqlcomm.Parameters.Add("#TotalNoRatio", SqlDbType.Decimal);
retval.Direction = ParameterDirection.ReturnValue;
You will need to specify the direction of you parameters as ParameterDirection.Output. You will also need to declare your parameters on your procedure as OUTPUT.
I have put together a small example below.
This is my procedure:
CREATE PROCEDURE [dbo].[procedureName]
#TotalNoRatio DECIMAL(18,2) OUTPUT,
#TotalRatio DECIMAL(18,2) OUTPUT
AS
SET #TotalNoRatio = 2
SET #TotalRatio = 3
This is my VB.NET code:
Using con As New SqlConnection(conString),
cmd As New SqlCommand("procedureName", con) With {.CommandType = CommandType.StoredProcedure}
con.Open()
cmd.Parameters.Add(New SqlParameter("#TotalNoRatio", SqlDbType.Decimal) With {.Direction = ParameterDirection.Output})
cmd.Parameters.Add(New SqlParameter("#TotalRatio", SqlDbType.Decimal) With {.Direction = ParameterDirection.Output})
cmd.ExecuteNonQuery()
lTotal1.Text = "TotalNoRatio: " & cmd.Parameters("#TotalNoRatio").Value.ToString()
lTotal2.Text = "TotalRatio: " & cmd.Parameters("#TotalRatio").Value.ToString()
End Using
This is a screenshot of the output:
On a seperate note consider turning Option Strict On:
Restricts implicit data type conversions to only widening conversions, disallows late binding, and disallows implicit typing that results in an Object type.
cmd.Parameters("#TotalNoRatio").Value returns type Object. You should be appending .ToString() to it if you're assigning to Label.Text.
Also note that I have implemented Using. You may already have, it's difficult to tell but if you haven't it's worth doing:
Sometimes your code requires an unmanaged resource, such as a file handle, a COM wrapper, or a SQL connection. A Using block guarantees the disposal of one or more such resources when your code is finished with them. This makes them available for other code to use.

For loop cursor in teradata

In my Teradata Stored Procedure, I want to have a for loop cursor against a dynamic sql.
Below is the code snippet
SET get_exclude_condition = '';
SET colum_id = 'SELECT MIN (parent_criteria_id) ,MAX (parent_criteria_id) FROM arc_mdm_tbls.intnl_mtch_criteria WHERE act_ind = 1 AND criteria_typ = ''Exclude'' AND mtch_technique_id ='||mtch_technique_id||';' ;
PREPARE input_stmt FROM colum_id;
OPEN flex_cursor;
FETCH flex_cursor INTO parent_criteria_id_min , parent_criteria_id_max ;
CLOSE flex_cursor;
SET get_exclude_condition = '';
WHILE (parent_criteria_id_min <= parent_criteria_id_max)
DO
SET get_exclude_condition = get_exclude_condition || '( ';
SET for_loop_stmt = 'SELECT criteria FROM arc_mdm_tbls.intnl_mtch_criteria WHERE act_ind = 1 AND mtch_technique_id ='||mtch_technique_id||' AND criteria_typ= ''Exclude'' AND parent_criteria_id ='||parent_criteria_id_min||';';
FOR for_loop_rule AS c_cursor_rule CURSOR FOR
for_loop_stmt
DO
Can I declare a for loop cursor like this ?
Or do I need to have something like this only ?
FOR for_loop_rule AS c_cursor_rule CURSOR FOR
SELECT rule_id
FROM arc_stage_tbls.assmt_scoring_rules
WHERE rule_typ = :v_RuleType
ORDER BY rule_id
DO
I mean can I first frame the dynamic sql and then have a for loop cursor on top of that or with the cursor declaration only I need to have a static sql query ?
Please clarify.
While you haven't posted everything that the stored procedure is trying to accomplish, it does appear that what you are asking can be accomplished using SET based logic and not looping through a cursor. If you need to parameterize the 'mtch_technique_id' you can use a Teradata macro which will allow you to maintain a SET based approach.
Here is the SQL for creating a macro that returns a result set based on my interpretation of what your snippet of the stored procedure is trying to accomplish:
REPLACE MACRO {MyDB}.Intnl_Mtch_Criteria(mtch_technique_id INTEGER) AS
(
SELECT criteria
FROM arc_mdm_tbls.intnl_mtch_criteria
WHERE act_ind = 1
AND (much_technique_id, criteria_typ) IN
(SELECT MIN((parent_criteria_id), MAX (parent_criteria_id)
FROM arc_mdm_tbls.intnl_mtch_criteria
WHERE act_ind = 1
AND criteria_typ = 'Exclude'
AND mtch_technique_id = :mtch_technique_id;
);

Result type from SQL Server stored procedure

Ok so I'm calling a stored procedure and I'm unsure of what type my VB.net code will be receiving.
Here's the stored procedure:
#IDNo varchar(Max)
AS
select a.IDNo,
p.EMAIL
from person p
left join customer a on p.person_id=a.person_id
where (a.IDNo=#IDNo)
Here's my VB so far;
resultSet = thisDataCxt.sp_GetEmail(IDNo).FirstOrDefault()
My question is, what type should resultSet be? Can I make it an Object? If so how do I access its IDNo and EMAIL properties.
Also need to bear in mind I'm using this to see if there are no results back (aka IDNo didn't have a match) so I need to test if resultSet is NULL.
Why cant you use Dataset & datatables and store the sp output in that.Then try to iterate the values through it if datatable has more than 0 rows.
It's going to be whatever you've mapped the result of the FunctionImport sp_getEmail to, probably a ComplexType. It's not going to be a set, per se, as you're taking the FirstOrDefault.
Incidentally, prefixing your SPs with sp_ is bad practice. http://sqlserverpedia.com/blog/sql-server-bloggers/stored-procedure-performance-using-%E2%80%9Csp_%E2%80%9D-prefix-%E2%80%93-myth-or-fact/
Check this sample code.
cmd.CommandText = "your proc name";
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param1 = cmd.Parameters.Add("#param1", SqlDbType.VarChar, 255);
param1.Direction = ParameterDirection.Input;
SqlParameter param2 = cmd.Parameters.Add("#param2", SqlDbType.Int, 8);
param2.Direction = ParameterDirection.OutPut;
cmd.ExecuteNonQuery();
Now you have your output value in #param2.

"Must declare the variable #myvariable" error with ADO parameterized query

i am trying to use parameterized queries with ADO. Executing the Command object throws the error:
Must declare the variable '#filename'
i declare the parameter #filename using CreateParameter/Append:
sql := 'INSERT INTO Sqm(Filename, data) VALUES(#filename, #data)';
command := CoCommand.Create;
command.Set_ActiveConnection(Connection.ConnectionObject);
command.Set_CommandText(sql);
command.Set_CommandType(adCmdText);
command.Parameters.Append(Command.CreateParameter('#filename', adLongVarWChar, adParamInput, -1, Filename));
command.Parameters.Append(Command.CreateParameter('#data', adLongVarWChar, adParamInput, -1, xml);
command.Execute({out}recordsAffected, EmptyParam, adCmdText or adExecuteNoRecords);
What am i doing wrong?
As far i know ADO doesn't supports named parameters in SQL sentences (SELECT, INSERT, UPDATE), so you must use the ? char to indicate the parameter
sql := 'INSERT INTO Sqm(Filename, data) VALUES(?, ?)';
and then assign the parameters values in the same order as are used in the sql sentence.
ADO 2.6 Introduces the NamedParameters property, but it seems which only works with stored procedures.
try this
uses ADODB, DB;
...
...
... and then in some event handler (e.g. button click),
var
aCommand :TADOCommand;
begin
aCommand := TADOCommand.create(self);
aCommand.ConnectionString := 'build the connection string or use TADOConnection and assign to Connection property instead of ConnectionString property';
aCommand.commandText := 'INSERT INTO Sqm(Filename, data) VALUES(:filename, :data);';
aCommand.parameters.paramByName('filename').value := 'test';
aCommand.parameters.paramByName('data').value := 'some data';
aCommand.execute;
aCommand.free;
end;
I have been using parameter by names this way for TADOCommand and TADOQuery with no problem.
Use Parameters.AddWithValue as shown below
connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Jet OLEDB:Database Password=RainbowTrout;";
InsertQry = "Insert into Sections(Name, PartNumber, VersionNumber, Channel, Address, Status, IPAddr) "
+ "values(#SectionName, #PartNumber, #VersionNumber, #Channel, #Address, #Status, #IPAddr)";
NewCfgConnection.ConnectionString = string.Format(connectionString, ConfigFN);
NewCfgCommand.Connection = NewCfgConnection;
NewCfgCommand.CommandText = InsertQry;
NewCfgConnection.Open();
// Clear parameter values from last record
NewCfgCommand.Parameters.Clear();
// Insert record into sections table - set parameters
NewCfgCommand.Parameters.AddWithValue("#SectionName", sSectionName);
NewCfgCommand.Parameters.AddWithValue("#PartNumber", sPartNumber);
NewCfgCommand.Parameters.AddWithValue("#VersionNumber", sVersionNumber);
NewCfgCommand.Parameters.AddWithValue("#Channel", iChannel);
NewCfgCommand.Parameters.AddWithValue("#Address", iAddress);
NewCfgCommand.Parameters.AddWithValue("#Status", iStatus);
NewCfgCommand.Parameters.AddWithValue("#IPAddr", iIP);
NewCfgCommand.ExecuteNonQuery();

Resources