How to use ASP variables in SQL statement - sql

<%
postit = request.querystring("thispost")
response.write(postit)
%>
postit is the variable. The response.write works and this is all above the SQL statement below.
This is the SQL however when I add the postit variable I get this error message:
delCmd.CommandText="DELETE * FROM post WHERE (pos_ID = postit )"
Microsoft Access Database Engine error '80040e10'
No value given for one or more required parameters.
/student/s0190204/wip/deleterecord.asp, line 32

Add a parameter to the SQL:
delCmd.CommandText="DELETE * FROM post WHERE (pos_ID = ?)"
delCmd.Parameters.Append delCmd.CreateParameter("posid", adInteger, adParamInput) ' input parameter
delCmd.Parameters("posid").Value = postit

Couple of things that will help you in the future
Use Option Explicit to avoid hiding issues that will come back to bite you later on
Use ADODB.Command object, which is very versatile enabling to do a range of database calls, from simple dynamic SQL statements to Stored Procedures without the risk of SQL injection.
There are a few tips that can speed things up when using the ADODB.Command object in your code which will be demonstrated in the example below (assumes you already have a connection string stored in a global config call gs_connstr);
<%
Option Explicit
Dim postit
postit = Request.QueryString("thispost")
'Always do some basic validation of your Request variables
If Len(postit) > 0 And IsNumeric(postit) Then CLng(postit) Else postit = 0
Dim o_cmd, o_rs, a_rs, i_row, i_rows, l_affected
Dim SQL
'SQL statement to be executed. For CommandType adCmdText this can be any dynamic
'statement, but adCmdText also gives you an added bonus - Parameterised Queries
'instead of concatenating values into your SQL you can specify placeholders (?)
'that you will define values for that will get passed to the provider in the order
'they are defined in the SQL statement.
SQL = "DELETE * FROM post WHERE (pos_ID = ?)"
Set o_cmd = Server.CreateObject("ADODB.Command")
With o_cmd
'ActiveConnection will accept a Connection String so there is no need
'to instantiate a separate ADODB.Connection object the ADODB.Command object
'will handle this and also open the connection ready.
.ActiveConnection = gs_connstr
.CommandType = adCmdText
.CommandText = SQL
'When using Parameters the most important thing to remember is the order you
'appended your parameters to the Parameters collection as this will determine
'the order in which they are applied to your SQL query at execution. Because
'of this the name you give to your parameters is not important in terms of
'execution but I find specifying a meaningful name is best (especially when
'revisiting some code a few years down the line).
Call .Parameters.Append(.CreateParameter("#pos_ID", adInteger, adParamInput, 4))
'Parameter values can be passed in via the Execute() method using an Array
'without having to define the parameter values explicitly. You can also specify
'the records affected value to return number of rows affected by a DELETE,
'INSERT or UPDATE statement.
.Execute(l_affected, Array(postit))
End With
'Always tidy up after yourself, by releasing your object from memory, this will
'also tidy up your connection as it was created by the ADODB.Command object.
Set o_cmd = Nothing
%>

Try this code:
<% Dim postit, stringSQL, objectCon
postit = request.querystring("thispost")
Set objectCon = Server.CreateObject("ADODB.Connection")
objectCon.ConnectionString "Driver={SQL SERVER};Server=server_name;UID=user_name;PWD=password;Database=database_name" 'SET CONNECTION STRING OF YOUR DATABASE
stringSQL = "DELETE FROM post WHERE pos_id='" & postit & "'"
objectCon.Open
objectCon.Execute(stringSQL)
objectCon.Close() %>

You're not passing the value of postit to Access; instead, you're telling Access to find & use a variable called postit. Of course, said variable doesn't exist in Access -- it only exists in your code. The fix is just a couple of quote marks and a pair of ampersands.
delCmd.CommandText="DELETE * FROM post WHERE (pos_ID = " & postit & " )"
(Naturally, you should validate postit before you go sending it off to your database. A simple CDbl() can do the trick, assuming it's a numeric value.)

Here I'm trying to get the car_color of the car using the id of the car.
Now I can use the car_color record set in my code.
I would also recommend using CLng when passing in values, it'll prevent sql injections.
If the carID is not a number you'll get the following error:
"500 response from the server. Remember to open and close the sql connection."
Here is the code:
sql = "Select * from Cars Where ID = " & clng(carID)
rs.open
if not rs.eof then
carID = rs("car_ID")
carColor = rs("car_color")
end if
rs.close

More easy for delete, this way is useful when not need to check the recordset:
cn.open "yourconnectionstring"
cn.execute "DELETE * FROM post WHERE pos_ID = " & request.querystring("thispost")
cn.close

Related

MS Access crashes binding RS to a form from SQL Server stored procedure

I am just starting to move our Access DB to SQL Server and am having trouble.
I have a stored procedure that successfully returns rows to an ado recordset.
When I try to bind the rs containing the results of the stored procedure to the Access form, Access crashes without displaying any error messages. I'm on O365 32b and SQL Server 2019.
Here's the code:
Dim sSQL As String, rs As ADODB.Recordset
1 sSQL = "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
2 ADOConn.ConnectionString = conADO
4 ADOConn.Open
6 Set rs = New ADODB.Recordset
7 rs.CursorLocation = adUseClient
8 rs.Open sSQL, ADOConn
10 Set Me.Recordset = rs ' Access crashes here
. . .
Any help would be greatly appreciated!
tia.
SR
Ok, are you previous using ADO, or are you just introducing this?
In most cases, you are better off to just use a view. (replace the access query with a linked view), and then continue useing client side where clauses or filters (access will ONLY pull down the rows you request). So linked views are often a better choice and much less work (in fact, even existing filter for a open report etc. will work and only critera matching the were clause records are pulled.
And in most cases, i don't introduce ADO.
So for a PT query, I often do this:
dim rs as DAO.RecordSet
with CurrentDb.queryDefs("qryPt")
.SQL = "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
set rs = .OpenRecordSet
end with
So, above assumes you have a pt query called qryPt. This also means that you never deal with or worry about connection strings in code. The pt query has the connection. (and your re-link code now can re-link tables and pt queries).
I ONLY suggest the above as a FYI in case that you introducing ADO for calling store procedures, and the rest of the application was previous DAO. If the application was previous DAO, then leave it alone, and use above approach for your PT queries - even code that needs to call store procedures.
Access tends to try and parse the query text to get filters/sorts/etc to work, and if it isn't a plain syntax error but isn't Access SQL either, strange things tend to happen, mostly crashes.
Try adding a comment up front to make sure Access knows not to parse:
sSQL = "-- Access no parse pls" & vbCrLf & "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
The content of the comment is not relevant, of course, its purpose is to immediately cause a syntax error when Access tries to parse it as Access SQL (which doesn't have comments)

VBA - MariaDB - Query cannot be updated because it contains no searchable columns to use as a key

I am using MariaDB and VBA to read/write a flat database using ADODB. This is not by choice however I've been asked to make it work in this manner. An alternative would be to directly use SQL queries however this is a port of a very old VB3 application.
Here is my code that connects to the database, pulls back all records, updates the last record, then calls update to effectively write it back to the database
Global DB As New ADODB.Connection
Global TD As New ADODB.Recordset
DB.Open "Driver={MariaDB ODBC 2.0 Driver};Server=localhost;UID=???;PWD=???;DB=sf_log;Port=3306"
Dim query As String: query = "SELECT * FROM `" & TableName & "` ORDER BY `Record ID`"
TD.CursorLocation = adUseServer
TD.CursorType = adOpenDynamic
TD.Open query, DB, adOpenKeyset, adLockOptimistic
TD.MoveLast
Dim TestColumnField as string
TestColumnField = TD.Fields("TestColumn") 'This returns the correct value from the database indicating the connection was successful
TD.Fields("TestColumn") = "test"
TD.UpdateBatch (adAffectCurrent) ' This line throws the error
Error that is reported is "Query cannot be updated because it contains no searchable columns to use as a key"
The database is a flat relationship-less database with no keys. I have tried setting "record id" to be a primary key with no luck.
Is this error due to MariaDB not implementing/supporting ADODB recorset? Is it due to my database structure? Or is it simply I am utilising the ADODB recorset incorrectly?
Edit: Here is an example that shows you do not need an SQL update statement. You can simply select the data and call Update.
http://www.accessallinone.com/updating-adding-and-deleting-records-in-a-recordset/
Sub ADODBUpdating()
Dim sql As String
Dim rs As adodb.Recordset
sql = "SELECT * FROM tblTeachers WHERE TeacherID=5"
Set rs = New adodb.Recordset
rs.Open sql, CurrentProject.Connection, adOpenDynamic, adLockOptimistic
'Open RecordSet
With rs
If Not .BOF And Not .EOF Then
.MoveLast
If .Supports(adUpdate) Then
![FirstName] = "x" & ![FirstName]
.Update
End If
End If
.Close
End With
Server side cursor implementation seems to be limited, use client side cursors (DB.CursorLocation = adUseClient) instead.
1.) You can't do an update in SQL with a SELECT-Statement. Instead use the UPDATE-Statement.
2.) Dont't try to update all the records. Only Update the single row you want to update. As you write this should be the last record.
You update the testfield and you have to be sufficiently specific in the WHERE-Clause, that you only select the one and only record record you want to update.

Calling scalar UDF function from ms access

I am trying to call a scalar function from my database in ms access.
This function should return one row of my salted and hashed parameters.
My initial attemt looked like this and returned the following error: "undefined function 'dbo.SaltAndHashPassword' in expression"
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("SELECT dbo.SaltAndHashPassword('" & Me.txtWW & "','" & Me.salt & "') as salted", dbOpenSnapshot, dbReadOnly)
I tried the solution from this question but I got the error "object required"
I also tried the solution from this question but I can't get it to work(probably due to wrong parameters)
Can anybody help me with this problem?
Thanks in advance.
You can't use CurrentDbin that case. You have to set a Connection object to the server/db where the dbo.SaltAndHashPassword function is stored (the example you mention uses a connection, even if the code to set it up is not shown), since it is totally unknown from Access.
Alternatively you can create a passthru query in Access and use DAO. I find it easier and it avoids creating yet another external reference.
Something like:
Set db = CurrentDb()
'Create a temporary passthrough query '
Set ptq = db.CreateQueryDef("")
'set ODBC connection '
ptq.Connect = "your connect string"
ptq.SQL = "SELECT * from your SQL"
ptq.ReturnsRecords = True
Set rs = ptq.OpenRecordset(dbOpenSnapshot)

Rowset does not support scrolling backward

I am trying to query a MySQL database with the below code:
'declare the variables
Dim Connection
Dim Recordset
Dim SQL
'declare the SQL statement that will query the database
SQL = "SELECT * FROM CUSIP"
'create an instance of the ADO connection and recordset objects
Set Connection = CreateObject("ADODB.Connection")
Set Recordset = CreateObject("ADODB.Recordset")
'open the connection to the database
Connection.Open "DSN=CCS_DSN;UID=root;PWD=password;Database=CCS"
Recordset.CursorType=adOpenDynamic
'Open the recordset object executing the SQL statement and return records
Recordset.Open SQL,Connection
Recordset.MoveFirst
If Recordset.Find ("CUSIP_NAME='somevalue'") Then
MsgBox "Found"
Else
MsgBox "Not Found"
End If
'close the connection and recordset objects to free up resources
Recordset.Close
Set Recordset=nothing
Connection.Close
Set Connection=nothing
Whenever I execute the above I get an error 'rowset does not support scrolling backward', any suggestions?
adOpenDynamic is not declared in VBScript and therefore equals Empty, which gets converted to 0 when you assign the CursorType property.
0 is adOpenForwardOnly, and forward only does not support moving backwards, an ability the Find method wants.
You should replace adOpenDynamic with its literal value:
Recordset.CursorType = 2 'adOpenDynamic
To avoid this class of errors altogether, place Option Explicit as the first line of your script.
That is because the rowset does not permit backward moves; as the error message suggests. Your code is not using them; so you should replace the line
Recordset.CursorType=adOpenDynamic
with
Recordset.CursorType=adOpenForwardOnly (or the equivalent value 0)
Better leave the line altogether; the default is forward cursor.

How to make a parametrized SQL Query on Classic ASP?

Can someone show me the simplest way of perform a parametrized SQL query using Classic ASP in VBscript?
A compilable example would be best.
Use the adodb.command object.
with createobject("adodb.command")
.activeConnection = application("connectionstring")
.commandText = "select * from sometable where id=?"
set rs = .execute( ,array(123))
end with
I would also advise to use a custom db access object instead of using adodb directly. This allows you to build a nicer api, improves testability and add hooks for debuging/logging/profiling. Secondly you can add request scoped transactions with implicit rollback's on errors using the class_terminiate event. Oure db access object offers the following query api
call db.execute("update some_table set column=? where id=?", array(value, id))
set rs = db.fetch_rs("select * from some_table where id=?", array(id))
count = db.fetch_scalar("select count(*) from some_table where column > ?", array(value))
I'm assuming you are referring to a parameterized SQL Query. If this is the case, then the VBScript code would look something like this:
Set adoCon = Server.CreateObject("ADODB.Connection")
adoCon.Open "connectionstring"
SET cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = adoCon
cmd.CommandType= adCmdStoredProc
cmd.CommandText = "GetCustomerByFirstName"
cmd.Parameters.Append cmd.CreateParameter("#FirstName",adVarchar,adParamInput,50,"John")
Set Rec = cmd.Execute()
While NOT Rec.EOF
'code to iterate through the recordset
Rec.MoveNext
End While
UPDATE: You need to include the ADOVBS.inc file for the constants to be recognized.
Here's a link: ADOVBS.inc
Another option to including adovbs.inc is to add a reference to the following type library near the top of your ASP. Supposedly this has better performance than an include:
<!--METADATA TYPE="TypeLib" NAME="ADODB Type Library" UUID="00000205-0000-0010-8000-00AA006D2EA4" FILE="C:\Program Files\Common Files\System\ado\msado15.dll" VERSION="2.5" -->
Here is a list of some type libraries.