use SQL Query in asp to populate scripting dictionary - sql

this is an answer I received from another question. I was just wondering how I use an SQL Query in asp to add users to the scripting dictionary using a database instead of writing them manually.
Set bannedUsers = CreateObject("Scripting.Dictionary")
bannedUsers.Add "johnsmith", True
bannedUsers.Add "cmanson", True
...
For Each opt In document.getElementById("frmNew").options
If opt.selected And bannedUser.Exists(opt.text) Then
MsgBox "This user is banned."
End If
Next

You need to establish a connection to your database (in case it isn't already established), e.g.:
connectionString = "..."
Set conn = CreateObject("ADODB.Connection")
conn.open connectionString
This place has a collection of connection strings for various database backends.
With the connection established you run a query against the database. There are several ways to do this, e.g. like this:
query = "SELECT fieldname FROM table WHERE condition"
Set cmd = CreateObject("ADODB.Command")
cmd.CommandText = query
Set rs = cmd.Execute
or like this:
query = "SELECT fieldname FROM table WHERE condition"
Set rs = CreateObject("ADODB.Recordset")
rs.CursorPosition = 3
rs.open query, conn, 3, 1
Adjust fieldname, table and condition according to your actual data and requirements.
Fill the dictionary with the values from the database like this:
Set bannedUsers = CreateObject("Scripting.Dictionary")
Do Until rs.EOF
bannedUsers.Add rs("fieldname").Value, True
rs.MoveNext
Loop
If the table doesn't have a unique index on fieldname you may want to check the dictionary for the existence of the key before adding it:
If Not bannedUsers.Exists(rs("fieldname").Value) Then
bannedUsers.Add rs("fieldname").Value, True
End If
Since you're querying a database anyway you don't even have to use a dictionary. You could disconnect the recordset and check it directly for user names:
query = "SELECT fieldname FROM table WHERE condition"
Set bannedUsers = CreateObject("ADODB.Recordset")
bannedUsers.CursorPosition = 3
bannedUsers.open query, conn, 3, 1
bannedUsers.ActiveConnection = Nothing 'disconnect recordset
For Each opt In document.getElementById("frmNew").options
If opt.selected Then
bannedUsers.Filter = "[fieldname] = '" & opt.text & "'"
If bannedUser.recordCount > 0 Then
MsgBox "This user is banned."
End If
End If
Next

This should do :
Set bannedUsersSet = conn.execute "SELECT DISTINCT LOGIN FROM BANNED_USERS /* Here goes your query */"
Set bannedUsers = CreateObject("Scripting.Dictionary")
While not bannedUsersSet.EOF
bannedUsers(bannedUsersSet("LOGIN")) = True
bannedUsersSet.MoveNext
WEnd
bannedUsersSet.close
Set bannedUsersSet = Nothing

Related

Check if table in Oracle database is empty using VBA and SQL COUNT(*)

I need how to find if a given table is empty in an Oracle database (Oracle 11g) to be specific using VBA inside of PowerAdmin Server Monitor's "run script" feature.
SELECT COUNT(*) FROM table; correctly returns "COUNT(*)" as 0. img of result
I need to find a way to check that result if it is 0 or not.
This is a redacted version of the script colleague uses to access the database for slightly different purposes, I prefer if we could continue from this
Dim strConnect
Dim strSQL
Dim adoConnection
Dim adoRecordset
strConnect = "Driver={Oracle in OraClient11g_home1_32bit};" & _
"Dbq=database;" & _
"Uid=user;" & _
"Pwd=password"
strSQL = "SELECT COUNT(*) FROM table;;"
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Open strConnect
Set adoRecordset = CreateObject("ADODB.Recordset")
adoRecordset.ActiveConnection = adoConnection
adoRecordset.Source = strSQL
adoRecordset.Open
[check if query result is the number 0 here]
adoRecordset.Close
adoConnection.Close
I need something that would look like
If queryresult = 0 then
SendNotification = True
Details = "table is empty"
End If
Any help would be appreciated. The more ELI5 the better.
After you execute a query in ADO, the recordset points to the first record, and you can access the fields of that first record per index (0-based).
The result of your count(*)-query is always one row with one column, holding the number of records. So you can access the number of rows with adoRecordset(0) (=first field of first record)
You could create a function to fetch the number of records:
Const strConnect = "..."
Function CountValues(tableName As String) As Long
Dim strSQL As String
strSQL = "SELECT COUNT(*) FROM " & tableName
Dim adoConnection
Dim adoRecordset
On Error GoTo CountValues_ERROR
Set adoConnection = CreateObject("ADODB.Connection")
Set adoRecordset = CreateObject("ADODB.Recordset")
adoConnection.Open strConnect
adoRecordset.ActiveConnection = adoConnection
adoRecordset.Source = strSQL
adoRecordset.Open
Dim res
res = adoRecordset(0)
CountValues = CLng(res)
GoTo CountValues_EXIT
CountValues_ERROR:
MsgBox "An error occurred fetching data: " & Err.Number & " " & Err.Description
CountValues_EXIT:
If adoRecordset.State <> 0 Then adoRecordset.Close
If adoConnection.State <> 0 Then adoConnection.Close
End Function
N.B.: If I where you, I would switch to early binding. Add a reference to the ADODB library and use
Dim adoConnection As ADODB.Connection
Dim adoRecordset As ADODB.RecordSet
Set adoConnection = new ADODB.Connection
Set adoRecordset = new ADODB.RecordSet

VBA Recordset doesn't return all fields

I just startied working with this database and I have a small problem.
So the main idea behind this is to use VBA to get needed information from database that I can use later on.
I am using ADO recordset and connect sting to connect to server. All is fine apart from one problem: when I am creating RecordSet by using SQL request it only returns one field when i know there should me more. At the moment I think that RecordSet is just grabbing first result and storing it in but looses anything else that should be there. Can you please help me.
Here is my code:
'Declare variables'
Dim objMyConn As ADODB.Connection
Dim objMyCmd As ADODB.Command
Dim objMyRecordset As ADODB.Recordset
Dim fldEach As ADODB.Field
Dim OrderNumber As Long
OrderNumber = 172783
Set objMyConn = New ADODB.Connection
Set objMyCmd = New ADODB.Command
Set objMyRecordset = New ADODB.Recordset
'Open Connection'
objMyConn.ConnectionString = "Provider=SQLOLEDB;Data Source=Local;" & _
"Initial Catalog=SQL_LIVE;"
objMyConn.Open
'Set and Excecute SQL Command'
Set objMyCmd.ActiveConnection = objMyConn
objMyCmd.CommandText = "SELECT fldImage FROM tblCustomisations WHERE fldOrderID=" & OrderNumber
objMyCmd.CommandType = adCmdText
'Open Recordset'
Set objMyRecordset.Source = objMyCmd
objMyRecordset.Open
objMyRecordset.MoveFirst
For Each fldEach In objMyRecordset.Fields
Debug.Print fldEach.Value
Next
At the moment Debug returns only one result when it should return two because there are two rows with the same OrderID.
The recordset only opens a single record at a time. You are iterating through all the fields in a single record. Not each record in the recordset.
If your query returns two records, you need to tell the Recordset to advance to the next one.
A query returns one recordset which has some number of records which have some number of fields.
You are iterating through the fields only for one record in the returned recordset.
You can do this with a few ways, but I generally do something like:
objMyRecordset.MoveFirst
Do
If Not objMyRecordset.EOF Then
debug.print "Record Opened - only returning 1 field due to SQL query"
For Each fldEach In objMyRecordset.Fields
Debug.Print fldEach.Value
Next
'this moves to the NEXT record in the recordset
objMyRecordset.MoveNext
Else
Exit Do
End If
Loop
Note that if you want to include more fields you will need to modify this line:
objMyCmd.CommandText = "SELECT fldImage FROM tblCustomisations WHERE fldOrderID=" & OrderNumber
To include whatever additional fields you want returned.
In addition to the #enderland's answer, you can also have a disconnected RecordSet, that have all the values and fields ready for consumption. It's handy when you need to pass the data around or need to close the connection fast.
Here's a function that returns a disconnected RecordSet:
Function RunSQLReturnRS(sqlstmt, params())
On Error Resume next
' Create the ADO objects
Dim rs , cmd
Set rs = server.createobject("ADODB.Recordset")
Set cmd = server.createobject("ADODB.Command")
' Init the ADO objects & the stored proc parameters
cmd.ActiveConnection = GetConnectionString()
cmd.CommandText = sqlstmt
cmd.CommandType = adCmdText
cmd.CommandTimeout = 900 ' 15 minutos
collectParams cmd, params
' Execute the query for readonly
rs.CursorLocation = adUseClient
rs.Open cmd, , adOpenForwardOnly, adLockReadOnly
If err.number > 0 then
BuildErrorMessage()
exit function
end if
' Disconnect the recordset
Set cmd.ActiveConnection = Nothing
Set cmd = Nothing
Set rs.ActiveConnection = Nothing
' Return the resultant recordset
Set RunSQLReturnRS = rs
End Function
You are mixing up terms in your question which makes it unclear
In your first paragraph you describe a problem with "Fields", in the last paragraph you turn it into "Rows". Not exactly the same.
But whatever you are trying to achieve, the code you wrote will only return one field and one row.
If you want all FIELDS, your query should be:
objMyCmd.CommandText = "SELECT * FROM tblCustomisations WHERE fldOrderID=" & OrderNumber
If you want all ROWS, your loop should be:
objMyRecordset.MoveFirst
If Not objMyRecordset.BOF Then
While Not objMyRecordset.EOF
debug.print objMyRecordset!fldImage
RS.MoveNext
Wend
End If

Fetching values from sql 2005 using vbscript

I am designing a web page that will fetch records for a specific id and print the information.I am just trying to redirect user to other page if provided id does not exists.I tried the below code but when id is null its showing blank page instead of redirecting to desired page.
code:
<%
Set conn = Server.CreateObject("ADODB.Connection")
conn.ConnectionString= "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=eseva;Data Source=BHAGWAT-PC"
conn.open
set rs=Server.CreateObject("ADODB.recordset")
rs.Open "Select * from saat_bara where id='"&request.form("t1")&"'" , conn
if IsNull(rs.Fields("id").Value) then
response.redirect("end.asp")
else
while not rs.eof
response.Write("Token no:")
response.Write(rs.fields.item(0))
response.write("<br><br>")
response.Write("Name:")
response.Write(rs.fields.item(1))
response.write("<br><br>")
response.Write("Address:")
response.Write(rs.fields.item(2))
response.write("<br><br>")
response.Write("Bdate:")
response.Write(rs.fields.item(3))
response.write("<br><br>")
rs.movenext
wend
end if
%>
You can't check a field that does not exist against null. So:
rs.Open "Select * from saat_bara where id='"&request.form("t1")&"'" , conn
if rs.eof
response.redirect("end.asp")
else
while not rs.eof
...
end if
Update:
Listed somethings you may want to consider for the future;
Look into using the ADODB.Command object to build parameterised queries.
Protects against SQL Injection
Data type negotiation is done for you (no adding apostrophes in your query when dealing with string types).
No need to manual setup ADODB.Connection and close it as .ActiveConnection can take a connection string and build your ADODB.Connection for you and when your ADODB.Command is released so is the associated connection.
Return only the field you need in your SQL query instead of using SELECT * depending on the table size this can be very costly (in your code your only returning four fields).
If you are just displaying data to screen consider using .GetRows() to return an Array rather than using ADODB.Recordset for iterating through your returned resultset. Resources that would be otherwise used by the ADODB.Recordset can be released as all your data is contained in a 2 dimensional array.
Below is an example of your code using ADODB.Command and Arrays;
<%
Dim connstr, sql, cmd, rs, data
Dim row, rows
connstr = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=eseva;Data Source=BHAGWAT-PC"
sql = ""
sql = sql & "SELECT Field0, Field1, Field2, Field3 " & vbCrLf
sql = sql & "FROM saat_bara " & vbCrLf
sql = sql & "WHERE id = ?"
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
.ActiveConnection = connstr
.CommandType = adCmdText
.CommandText = sql
'As you put apostrophes around your id assumed it must be a varchar. If
'this is used as your primary key would be more efficient for it to be
'a numeric type like int, in which case you would use adInteger.
.Parameters.Append(.CreateParameter("#id", adVarChar, adParamInput, 50)
Set rs = .Execute(, Array(Request.Form("t1")))
If Not rs.EOF Then data = rs.GetRows()
'Release memory used by recordset
Call rs.Close()
Set rs = Nothing
End With
'Release memory and close connection used by command.
Set cmd = Nothing
If IsArray(data) Then
rows = UBound(data, 2)
For row = 0 To rows
'Consider not using Response.Write in your loop (taken from Bond's suggestion)
Call Response.Write("Token no:")
Call Response.Write(data(0, row))
Call Response.Write("<br><br>")
Call Response.Write("Name:")
Call Response.Write(data(1, row))
Call Response.Write("<br><br>")
Call Response.Write("Address:")
Call Response.Write(data(2, row))
Call Response.Write("<br><br>")
Call Response.Write("Bdate:")
Call Response.Write(data(3, row))
Call Response.Write("<br><br>")
Next
Else
'No data redirect
Call Response.Redirect("end.asp")
End If
%>

How to set controlsource of a textbox from SQL

I have a subform bound to a SQL statement. Inside the subform, I have a few text boxes bound to the fields of this SQL. However, I have another text box that needs to be bound to a field from a different SQL statement with criteria from the first one. My code looks like below:
Dim subform As Object
Dim formFilter As String
formFilter = "SELECT * FROM my_table_1"
Set subform = Me!my_subform.Form
subform.RecordSource = formFilter
subform.field1.ControlSource = "tb1f1"
subform.field2.ControlSource = "tb1f2"
...
subform.f3.ControlSource = "= SELECT TOP 1 tb2f3 FROM my_table_2 WHERE tb2f1 = '" & [tb1f1] & "' AND tb2f2 = '" & [tb1f2] "' ORDER BY tb2f4"
I cannot use a DLOOKUP function here directly, because I need to sort the table result.
Thanks in advance for your help.
I think I would simply create a little function to go get the result you want. It would probably be best to simply rework DLookup in your own function and add sort but I won't do that here.
First the form code. Notice I am not setting the recordsource, just the value which may not be what you want.
subform.f3 = fGet_tb2f3([tb1f1], [tb1f2])
Then the function code (put in your own error handling)
Public Function fGet_tb2f3(tblf1 as String,tblf2 as String) as String
Dim rst as dao.recordset
Dim db as database
set db = currentdb
set rst = db.openrecordset("SELECT TOP 1 tb2f3 FROM my_table_2 WHERE tb2f1 = '" & tb1f1 & "' AND tb2f2 = '" & tb1f2 "' ORDER BY tb2f4",dbopensnapshot
if not rst is nothing then
if not rst.eof then fGet_tb2f3 = rst!tb2f3
rst.close
set rst = nothing
end if
db.close
set db = nothing
end Function
You can't bind controls on the same form to 2 different recordsets. The only thing you could do is pull data from 2 different recordsets, but that's probably not the best way to do anything.
In order to do that, you'd have to create a second recordset and grab that value in it. Something like:
Dim db as Database
Dim rec as Recordset
Set db = CurrentDB
Set rec = db.OpenRecordset("SELECT TOP 1 tb2f3 FROM my_table_2 WHERE tb2f1 = '" & [tb1f1] & "' AND tb2f2 = '" & [tb1f2] "' ORDER BY tb2f4")
Me.MyControlName = rec(0)

Invalid Use of Property in VB6 Error. How to fix this?

Private Sub aTbBar_Change()
Set con = New ADODB.Connection
With con
.CursorLocation = adUseClient
.ConnectionString = "Provider=Microsoft.jet.oledb.4.0;persist security info=false;data source=" & App.Path & "\Event_Participants.accde"
.Open
End With
Set rs = New ADODB.Recordset
With rs
Set .ActiveConnection = con
.CursorType = adOpenDynamic
.Source = "select * from Participants"
.Open
'check from table if user and pwd matches
If rs.RecordCount <> 0 Then
rs.MoveFirst
While Not rs.EOF
If rs!Bar_Code_No = Val(Me.aTbBar) Then
Me.aTbName = rs!Full_Name
Me.aTbSection = rs!Section
Me.aTbArrtime = Time()
End If
rs.MoveNext
Wend
End If
.Close
Set rs = Nothing
End With
'save to the database
'check from table if user and pwd matches
Set rs = New ADODB.Recordset
With rs
Set .ActiveConnection = con
.CursorType = adOpenDynamic
.LockType = adLockOptimistic
.Source = "select * from Participants"
.Open
If rs.RecordCount <> 0 Then
rs.MoveFirst
While Not rs.EOF
If rs!Bar_Code_No = Val(Me.aTbBar) Then
.Update
rs!Arr_Time = Me.aTbArrtime
End If
rs.MoveNext
Wend
End If
End With
rs.Close
Set rs = Nothing
End Sub
Invalid Use of Proper error always occur when I type in to that textbox name aTbBar
The error occurs at Me.aTbName = rs!Full_Name. Can you help me on this one. Sorry, im new in this forums and in VB. I really need help
The default property triggered for a TextBox is the Text property. So, if there is a TextBox with the name Text1, then this statement: Text1 = "Hello" would be equivalent to Text1.Text = "Hello". But I always prefer using the property name along with the control name, when accessing it(ie, Text1.Text = "Hello").
Anyway, test it out by using this line: Me.aTbArrtime.text = rs!Full_Name
Another thing that I have in mind is, if you have used some other component, say a custom made TextBox control (instead of the default one), and in the case of load failure, VB would replace the control(the custom made textbox) with a PictureBox in your forms. For checking that, click on the TextBox in the form and view it's properties. And see whether the control type is a TextBox. If it is a PictureBox, then double check whether your OCX or DLL for the custom made textbox is present in the project.
A small suggestion on your SQL code is that, you could have included the comparison in your query itself, instead of looping through all the records. For example:
.Source = "select * from Participants WHERE Bar_Code_No = " & Val(Me.aTbBar.Text) & " LIMIT 1"
This would return a single record if it matches the Bar_Code_No. After executing this query, you only need to check if it returns any record. If so, a match is found. Otherwise, no match is found. By this way, you can avoid looping, which might make your program Non-Responding if the number of records in the table Participants is enormously large !
Hope this would help you. Wish you good luck :)