I'm setting a Session of MM_CustomerID in my code and then further down the page I need to insert the value of that session into a table. But each time I try to do this it comes up with an Invalid column name 'varCustomerID'.
At the top of the page I have this code;
<%
set rscustomerid = Server.CreateObject("ADODB.Recordset")
rscustomerid.ActiveConnection = CmdAddCustomer.ActiveConnection
rscustomerid.Source = "SELECT ##IDENTITY as MaxCustomersID FROM Customers"
rscustomerid.CursorLocation = 2
rscustomerid.LockType = 3
rscustomerid.Open()
Session("MM_CustomerID")=rscustomerid("MaxCustomersID")
Session("MM_UserAuthorization") = "5"
%>
Then further down, i'm trying to set a variable of varCustomerID to be equal to the MM_CustomerID session;
<%
varCustomerID = Session("MM_CustomerID")
%>
And then try inserting the value of that variable varCustomerID into the Orders table as follows;
<%
'Insert record into Orders recordset when form is submitted
'and store the unique OrderID
'Version Date: 09 August 2009
set CmdAddOrder = Server.CreateObject("ADODB.Command")
CmdAddOrder.ActiveConnection = MM_dbconn_STRING
CmdAddOrder.CommandText = "INSERT INTO Orders (OrderCustomer,OrderGrandTotal,OrderStatus) VALUES (varCustomerID,0.00,3)"
CmdAddOrder.CommandType = 1
CmdAddOrder.CommandTimeout = 0
CmdAddOrder.Prepared = true
CmdAddOrder.Execute()
%>
I wondered if anyone might be able to help? Perhaps there's an easier way of just inserting the session value into the table, instead of creating a variable for it?
Thanks.
You need to change the sql command text to:
"INSERT INTO Orders (OrderCustomer,OrderGrandTotal,OrderStatus) VALUES (" + varCustomerID + ",0.00,3)"
However you could be vulnerable to SQL injection... really you should parametrise this query:
http://aspnet101.com/aspnet101/tutorials.aspx?id=1
You need to cast varCustomerID to a string for the query. Slight change to Paul's answer should get you working but like he says you need to be careful of injection attacks.
"INSERT INTO Orders (OrderCustomer,OrderGrandTotal,OrderStatus) VALUES (" & varCustomerID & ",0.00,3)"
Related
I have a query called qryAlloc_Source that has two paramaters under one criteria:
>=[forms]![frmReportingMain]![txtAllocStart] And <=[forms]![frmReportingMain]![txtAllocEnd])
A have a separate query that ultimately references qryAlloc_Source (there are a couple queries in between), and that query runs fine when I double click it in the UI, but if I try to open it in VBA, I get an error. My code is:
Dim rst As Recordset
Set rst = CurrentDb.OpenRecordset("qryAlloc_Debits")
I am getting run-time error 3061, Too few parameters. Expected 2. I've read that I may need to build out the SQL in VBA using the form parameters, but it would be pretty complex SQL given that there are a few queries in the chain.
Any suggestions as to a workaround? I considered using VBA to create a table from the query and then just referencing that table--I hate to make extra steps though.
The reason you get the error when you just try to open the recordset is that your form is not open and when you try to access [forms]![frmReportingMain] it's null then you try to get a property on that null reference and things blow up. The OpenRecordset function has no way of poping up a dialog box to prompt for user inputs like the UI does if it gets this error.
You can change your query to use parameters that are not bound to a form
yourTableAllocStart >= pAllocStart
and yourTableAllocEnd <= pAllocEnd
Then you can use this function to get the recordset of that query.
Function GetQryAllocDebits(pAllocStart As String, pAllocEnd As String) As DAO.Recordset
Dim db As DAO.Database
Dim qdef As DAO.QueryDef
Set db = CurrentDb
Set qdef = db.QueryDefs("qryAlloc_Debits")
qdef.Parameters.Refresh
qdef.Parameters("pAllocStart").Value = pAllocStart
qdef.Parameters("pAllocEnd").Value = pAllocEnd
Set GetQryAllocDebits = qdef.OpenRecordset
End Function
The disadvantage to this is that when you call this now on a form that is bound to it it doesn't dynamically 'fill in the blanks' for you.
In that case you can bind forms qryAlloc_debts and have no where clause on the saved query, then use the forms Filter to make your where clause. In that instance you can use your where clause exactly how you have it written.
Then if you want to still open a recordset you can do it like this
Function GetQryAllocDebits(pAllocStart As String, pAllocEnd As String) As DAO.Recordset
Dim qdef As DAO.QueryDef
Set qdef = New DAO.QueryDef
qdef.SQL = "Select * from qryAlloc_Debits where AllocStart >= pAllocStart and pAllocEnd <= pAllocEnd"
qdef.Parameters.Refresh
qdef.Parameters("pAllocStart").Value = pAllocStart
qdef.Parameters("pAllocEnd").Value = pAllocEnd
Set GetQryAllocDebits = qdef.OpenRecordset
End Function
While a [Forms]!... reference does default to a form reference when a QueryDef is run from the GUI, it is actually just another Parameter in the query in VBA. The upshot is you don't have to recode your query/create a new one at all. Also, as #Brad mentioned, whether a parameter is in the final query of a chain of queries or not, you are able to refer to the parameter as if it is in the collection of the final query. That being the case, you should be able to use code similar to this:
Sub GetQryAllocDebits(dteAllocStart As Date, dteAllocEnd as Date)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rst As DAO.Recordset
Set db = CurrentDb()
Set qdf = db.QueryDefs("qryAlloc_Debit")
If CurrentProject.AllForms("frmReportingMain").IsLoaded Then
qdf.Parameters("[forms]![frmReportingMain]![txtAllocStart]") = [forms]![frmReportingMain]![txtAllocStart]
qdf.Parameters("[forms]![frmReportingMain]![txtAllocEnd]") = [forms]![frmReportingMain]![txtAllocEnd]
Else
qdf.Parameters("[forms]![frmReportingMain]![txtAllocStart]") = CStr(dteAllocStart)
qdf.Parameters("[forms]![frmReportingMain]![txtAllocEnd]") = CStr(dteAllocEnd)
End If
Set rst = qdf.OpenRecordset
Do Until rst.EOF
'...do stuff here.
Loop
Set rst = Nothing
Set qdf = Nothing
Set db = Nothing
End Function
If the referenced form is open, the code is smart enough to use the referenced controls on the form. If not, it will use the dates supplied to the subroutine as parameters. A gotcha here is that the parameters did not like when I set them as date types (#xx/xx/xx#), even if the field were dates. It only seemed to work properly if I set the params as strings. It didn't seem to be an issue when pulling the values straight out of the controls on the forms, though.
I know it's been a while since this was posted, but I'd like to throw in my tuppence worth as I'm always searching this problem:
A stored query can be resolved:
Set db = CurrentDb
Set qdf = db.QueryDefs(sQueryName)
For Each prm In qdf.Parameters
prm.Value = Eval(prm.Name)
Next prm
Set rst = qdf.OpenRecordset
For SQL:
Set db = CurrentDb
Set qdf = db.CreateQueryDef("", "SELECT * FROM MyTable " & _
"WHERE ID = " & Me.lstID & _
" AND dWeekCommencing = " & CDbl(Me.frm_SomeForm.Controls("txtWkCommencing")) & _
" AND DB_Status = 'Used'")
For Each prm In qdf.Parameters
prm.Value = Eval(prm.Name)
Next prm
Set rst = qdf.OpenRecordset
This assumes that all parameter values are accessible - i.e. forms are open and controls have values.
'I have two parameters in my recordset and I was getting the "Too few parameters. Expected 2" 'error when using an OpenRecordset in MS Access vba, and this is how I got around it and IT WORKS! see the below sub routine:
'Private Sub DisplayID_Click()
'1. I created variables for my two parameter fields xEventID and xExID as seen below:
Dim db As Database
Dim rst As Recordset
Dim xEventID As Integer
Dim xExId As Integer
'2. Sets the variables to the parameter fields as seen below:
Set db = CurrentDb
xEventID = Forms!frmExhibitorEntry!txtEventID
xExId = Forms!frmExhibitorEntry!subExhibitors!ExID
'3. Set the rst to OpenRecordSet and assign the Set the variables to the WHERE clause. Be sure to include all quotations, ampersand, and spaces exactly the way it is displayed. Otherwise the code will break!exactly as it is seen below:
Set rst = db.OpenRecordset("SELECT tblInfo_Exhibitor.EventID,tblInfo_Display.ExID, tblMstr_DisplayItems.Display " _
& "FROM tblInfo_Exhibitor INNER JOIN (tblMstr_DisplayItems INNER JOIN tblInfo_Display ON tblMstr_DisplayItems.DisplayID = tblInfo_Display.DisplayID) ON tblInfo_Exhibitor.ExID = tblInfo_Display.ExID " _
& "WHERE (((tblInfo_Exhibitor.EventID) =" & xEventID & " ) and ((tblInfo_Exhibitor.ExID) =" & xExId & " ));")
rst.Close
Set rst = Nothing
db.Close
'End Sub
I'm trying to update a classic ASP application and as part of the update I've tried to replace dynamic SQL using string concatenation with a parametrised query.
The problem is that the parameters won't accept a value which is longer than 210 characters.
I get the following error...
ADODB.Parameter error '800a0d5d'
Application uses a value of the wrong type for the current operation.
/admin/Save_product_subcategories.asp, line 30
My first attempt looks like this...
SQLString = "UPDATE Product_SubCategories
SET SubCategory=?, Description=?
WHERE SubCategoryID=?"
Set courseCommand = Server.CreateObject("ADODB.Command")
courseCommand.ActiveConnection = objConn
courseCommand.CommandText = SQLString
courseCommand.Parameters(0).value = cleanCategory
courseCommand.Parameters(1).Value = cleanDescription
courseCommand.Parameters(2).value = cleanSubCategoryId
I've tried manually setting the parameter type and increasing the size of the parameter...
courseCommand.Parameters(1).Type = 203
courseCommand.Parameters(1).Size = 300
courseCommand.Parameters(1).Type = adLongVarWChar
I've also tried creating a parameter with the command.CreateParameter method but that gives the same error.
param = courseCommand.CreateParameter(,,,,cleanDescription)
'or
param = courseCommand.CreateParameter(,adLongVarWChar,,,cleanDescription)
'or
param = courseCommand.CreateParameter(,adLongVarWChar,,300,cleanDescription)
courseCommand.Parameters(1) = param
I'm beginning to think that my only option is to go back to dynamic sql.
Edit:
I tried to Append the parameter instead of adding it to the collection using the array index but none of the parameters worked after that.
Provider error '80020005'
Type mismatch.
/admin/Save_product_subcategories.asp, line 31
For anyone else looking for this the answer is to use a Recordset.
SQLString = "select * from Product_SubCategories where 1=0"
Set rs= Server.CreateObject("ADODB.Recordset")
rs.open SQLString , objConn, 1,3 'open as keyset ,lock optimistic that will create empty recordset for you
' Add new record
rs.AddNew
'assign values
rs("SubCategoryID")=cleanSubCategoryId
rs("Description")=cleanDescription
rs("SubCategory")=cleanCategory
' send new record with values to database
rs.Update
'close recordset
rs.close
'destroy recordset object
se rs=nothing
I have a small adodb recordset I am trying to filter. This one is 6 records for our test customer.
For some reason the filter is taking 2 seconds to complete, and I am doing this around 30 times on my asp page. Thus, making my page really slow to load. The other recordset filters on this page are running fast.
I have tried setting different CursorLocations and CursorTypes..
Can anyone help me determine why this filter is so slow?
rsAvgPrice.Filter = "CommodityID = 13 AND CropYear = '12'"
Probably the whole query is executed again and only then the filter is being applied.
I would have one single loop over all the items, store the required data in local variables then have my own filter. Best efficiency, much better control.
For example, if you want the data filtered by those two fields, I would use Dictionary like this:
Dim oCommodity_CropYear_Data, curKey
Dim curCommodityID, curCropYear, curData
Set oCommodity_CropYear_Data = Server.CreateObject("Scripting.Dictionary")
Do Until rsAvgPrice.EOF
curCommodityID = rsAvgPrice("CommodityID")
curCropYear = rsAvgPrice("CropYear")
curKey = curCommodityID & "_" & curCropYear
curData = "field1: " & rsAvgPrice("somefield") & ", field 2: " & rsAvgPrice("other_field") & "<br />"
oCommodity_CropYear_Data(curKey) = oCommodity_CropYear_Data(curKey) & curData
rsAvgPrice.MoveNext
Loop
rsAvgPrice.Close
Then to extract the data in a loop:
For x=1 To 30
For y=1 To 12
curKey = x & "_" y
If oCommodity_CropYear_Data.Exists(curKey) Then
Response.Write("Data for Commodity " & x & " and CropYear " & y & ":<br />" & oCommodity_CropYear_Data(curKey)
End If
Next
Next
This is the general idea, hope you can use it for your actual needs.
I have resolved this issue.
The issue was when I declare a record set the following way, the cursor type gets set as adOpenForwardOnly and the cursor location to adUseServer. These settings cannot be changed if you fill your recordset using command.Execute.
Set cmd = Server.CreateObject("ADODB.Command")
cmd.CommandType = adCmdText
cmd.CommandText = mySQL
cmd.CommandTimeout = 3000
cmd.ActiveConnection = cn
Set rs = Server.CreateObject("ADODB.Recordset")
Set rs = cmd.Execute
Set cmd = Nothing
The way I resolved this was manually declaring a permanent recordset with its fields. Then I filled a temporary recordset using the command.execute. I then manually populated my declared recordset with the temporary recordset record by record. This allowed me to set the cursorlocation to adUseClient.
Thus speeding up the filter by leaps and bounds.
I have a reset button that goes like this:
<% If Request("Reset") = "Reset" Then
Dim cn
Dim strSQLCommand
Set cn = Server.CreateObject("ADODB.Connection")
cn.Open MM_DD_DB_STRING
For Each variableName in Request.Form
If Instr(variableName, "selected") = "1" Then
Dim prodCode
prodCode = Split(variableName, "selected_")(1)
strSQLCommand = "UPDATE DB.STOCK SET DUE_DATE= NULL WHERE ID=x'" & prodCode & "'"
cn.Execute strSQLCommand
End If
Next
cn.Close
Set cn = Nothing
End if
%>
If I click on reset I want the DUE_DATE only to be reset or rather = NULL
For now when I select a checkbox and click reset button it doesn't make the DUE_DATE field into null. But i used this code: UPDATE DB.STOCK SET DUE_DATE= NULL Am I doing something wrong?
Any help is appreciated. Thanks
As SearchAndResQ are suggesting in his comment to your question: Do a quick response.write before the execute call, do see if the query looks correct. If it looks fine, do a quick check directly into the database, to check if it accepts it.
Lastly check to see if your .asp site isn't errored. I suspect this, because you are doing a definition of a variable (dim prodCode) inside a for-loop, which will cause the page to error if the loop is repeated 2 or more times. Move this line outside the for-loop.
I'm trying to avoid using straight SQL queries in my web app. I looked around and have come to the conclusion that ADO Recordsets would be the best or at least safest tool for the job. I need to insert records into a database table. Unfortunately I'm at a loss as to how to get the identity value for the record which was just inserted. Here's a reduction of what I've got now:
<%
dim insertID, rs
set rs = Server.CreateObject("ADODB.Recordset")
rs.Open "my_table_name", conn, adOpenForwardOnly, adLockOptimistic
rs.AddNew()
Call m_map_values_to_rs(rs)
rs.Update()
insertID = rs("id")
rs.Close()
rs = Nothing
%>
The code I have is successfully inserting the record, but I can't for the life of me figure out how to get the id field of the Recordset to update after the insert. How can I get the identity column value back from this Recordset?
UPDATE - Here's the solution with regard to the code above.
I had to change the cursor type to adOpenKeyset instead of adOpenForwardOnly. After I did this the record is automatically updated with the "auto number" field's new value after the insert. However it is not what you think it is. The value of rs("id") doesn't become an integer or even a variant. It becomes some sort of Automation type and cannot be evaluated as a number. Nor can CInt() be used directly on that type for some reason. So what you must do is to convert the value to a string and then convert it to an Int. Here's how I managed that:
insertID = CInt( rs("id") & "" )
Thanks to Dee for their answer. It helped immensely.
This article explains the means of getting identity value with example code.
The relevant code snippet is:
<%
fakeValue = 5
set conn = CreateObject("ADODB.Connection")
conn.open "<conn string>"
sql = "INSERT someTable(IntColumn) values(" & fakeValue & ")" & _
VBCrLf & " SELECT ##IDENTITY"
set rs = conn.execute(sql)
response.write "New ID was " & rs(0)
rs.close: set rs = nothing
conn.close: set conn = nothing
%>