I am creating a login form for users to log into using a database. I was wondering if there is a way in which i could get the program to search the entire table instead of a certain item. Here is my code so far.
Dim UserInputtedUsername As String
Dim UserInputtedPassword As String
UserInputtedUsername = txtAdminUsername.Text
UserInputtedPassword = txtAdminPassword.Text
sqlrunnerQuery = "SELECT * FROM tblLogin"
daRunners = New OleDb.OleDbDataAdapter(sqlrunnerQuery, RunnerConnection)
daRunners.Fill(dsRunner, "Login")
If UserInputtedUsername = dsadminlogin.Tables("Login").Rows(0).Item(2) And UserInputtedPassword = dsadminlogin.Tables("Login").Rows(0).Item(3) Then
Form1.Show()
ElseIf MsgBox("You have entered incorrect details") Then
End If
End Sub
Instead if searching the (in-memory) DataSet for your user serach the database in the first place. Therefore you have to use a WHERE in the sql query(with guessed column names):
sqlrunnerQuery = "SELECT * FROM tblLogin WHERE UserName=#UserName AND PassWord=#PassWord"
Note that i've used sql-parameters to prevent sql-injection. You add them in this way:
daRunners = New OleDb.OleDbDataAdapter(sqlrunnerQuery, RunnerConnection)
daRunners.SelectCommand.Parameters.AddWithValue("#UserName", txtAdminUsername.Text)
daRunners.SelectCommand.Parameters.AddWithValue("#PassWord", txtAdminPassword.Text)
Now the table is empty if there is no such user.
If dsadminlogin.Tables("Login").Rows.Count = 0 Then
MsgBox("You have entered incorrect details")
End If
For the sake of completeteness, you can search a complete DataTable with DataTable.Select. But i prefer LINQ-To-DataSet. Here's a simple example:
Dim grishamBooks = From bookRow in tblBooks
Where bookRow.Field(Of String)("Author") = "John Grisham"
Dim weHaveGrisham = grishamBooks.Any()
Related
I have built a form with unbound fields designed so a user can input a date range, a facility name (these come from a combobox), and a badge number to generate a query in Access. I want to be able to return results within the selected date range for all facilities if the field is left blank or just the ones for a particular facility if one is selected. I also want to be able to limit the results to those that match an person's badge number.
So the possibilities I want would be:
Date Range = defined by user | Facility - All if not selected | Badge # = All if not selected
Date Range = defined by user | Facility - All if not selected | Badge # = defined by user
Date Range = defined by user | Facility - defined by user | Badge # = All if not selected
Date Range = defined by user | Facility - defined by user | Badge # = defined by user
I originally built it with just the date range and facility name and it worked fine. When I try to add in the Badge # it doesn't really work correctly.
My SQL for the WHERE TO section is:
WHERE (((Diversion.Transaction_Date) Between [Forms]![Parameters]![FromDate] And [Forms]![Parameters]![ToDate])
AND ((Diversion.Employee_Badge_Number)=[Forms]![Parameters]![BadgeNumber])
AND ((Diversion.Facility)=[Forms]![Parameters]![FacilitySelect]))
OR (((Diversion.Transaction_Date) Between [Forms]![Parameters]![FromDate] And [Forms]![Parameters]![ToDate])
AND ((Diversion.Facility)=[Forms]![Parameters]![FacilitySelect])
AND ((([Diversion].[Employee_Badge_Number]) Like [Forms]![Parameters]![BadgeNumber]) Is Null))
OR (((Diversion.Transaction_Date) Between [Forms]![Parameters]![FromDate] And [Forms]![Parameters]![ToDate])
AND ((Diversion.Employee_Badge_Number)=[Forms]![Parameters]![BadgeNumber])
AND ((([Diversion].[Facility]) Like [Forms]![Parameters]![FacilitySelect]) Is Null))
OR (((Diversion.Transaction_Date) Between [Forms]![Parameters]![FromDate] And [Forms]![Parameters]![ToDate])
AND ((([Diversion].[Employee_Badge_Number]) Like [Forms]![Parameters]![BadgeNumber]) Is Null)
AND ((([Diversion].[Facility]) Like [Forms]![Parameters]![FacilitySelect]) Is Null))
OR (((([Diversion].[Facility]) Like [Forms]![Parameters]![FacilitySelect]) Is Null));
To me, it looks like it is including the four possible results that I want to get from the form, but it isn't working right. For instance, if I leave the facility field blank, and define the badge number, it is still giving me all of the results. If I define the facility and define the badge number it does give me the correct results.
Any ideas?
This might give you some ideas building a dynamic query with multiple criteria values. In this example the user can pick any number of the criteria. It is written in VB.Net. It works with Access. I check each field to see if any criteria was provided then append it to the query if there is a valid value.
I used Interpolated strings just because it is easier to see where the spaces go. The alternative is:
String.Format("RoasterId = {0} ", itgRoaster)
I also used a String builder which is an efficient way to alter strings without the overhead of creating and disposing of them with each append. You could just use &= if this is not available in VBA.
Dim bolNeedAnd As Boolean = False
Dim sb As New Text.StringBuilder
sb.Append("SELECT Coffees.ID, Coffees.[Name], Coffees.RoasterID, Roasters.[Name], Coffees.[Type],Coffees.Rating, Coffees.Comment, Coffees.Description, Coffees.Roast, Coffees.IsExtraBold, Coffees.IsFavorite
From Coffees Inner Join Roasters on Coffees.RoasterID = Roasters.ID Where ")
If itgRoaster <> 0 Then
sb.Append($"RoasterID = {itgRoaster} ")
bolNeedAnd = True
End If
If strRoast <> "" Then
If bolNeedAnd Then
sb.Append($"AND Roast = '{strRoast}' ")
Else
sb.Append($"Roast = '{strRoast}' ")
End If
bolNeedAnd = True
End If
If strType <> "" Then
If bolNeedAnd Then
sb.Append($"AND Type = '{strType}' ")
Else
sb.Append($"Type = '{strType}' ")
End If
bolNeedAnd = True
End If
If strRating <> "" Then
If bolNeedAnd Then
sb.Append($"AND Rating = '{strRating}' ")
Else
sb.Append($"Rating = '{strRating}' ")
End If
bolNeedAnd = True
End If
If bolBold Then
If bolNeedAnd Then
sb.Append("AND IsExtraBold = 1 ")
Else
sb.Append("IsExtraBold = 1 ")
End If
bolNeedAnd = True
End If
If bolFavorite Then
If bolNeedAnd Then
sb.Append("AND IsFavorite = 1 ")
Else
sb.Append("IsFavorite = 1 ")
End If
End If
sb.Append("Order By Coffees.[Name];")
Debug.Print(sb.ToString)
Dim cmd As New OleDbCommand With {
.Connection = cn,
.CommandType = CommandType.Text,
.CommandText = sb.ToString}
this question is related to my previous questions
I'm currently working on a Registration form where all the details of a student are save in a text file.
I populated the combobox using a textfile.
The format of these values are for example: (code~school name) SCH001~Saint
Thomas College
this is how I saved the details in a text file:
Dim firstname, lastname, email, mobile, level, currentschool, currenttrack, institution1, institution2, institution3, institution4, institution5, institution6, courses1, courses2, courses3, macaddress, eventcode, idseq, filename, logfiledirectory, targetdirectory, log, configdir, printschool As String
firstname = txtFName.Text
lastname = txtLName.Text
email = txtEmail.Text
mobile = txtMobile.Text
level = cmbLevel.Text
currenttrack = cmbCurrentTrack.Text
printschool = cmbCurrentSchool.Text
currentschool = cmbCurrentSchool.SelectedValue
institution1 = cmbInstitution1.SelectedValue
institution2 = cmbInstitution2.SelectedValue
institution3 = cmbInstitution3.SelectedValue
institution4 = cmbInstitution4.SelectedValue
institution5 = cmbInstitution5.SelectedValue
institution6 = cmbInstitution6.SelectedValue
courses1 = cmbCourse1.SelectedValue
courses2 = cmbCourse2.SelectedValue
courses3 = cmbCourse3.SelectedValue
If mobile = "" Then
mobile = "09000000000"
End If
If firstname = "" Or lastname = "" Or email = "" Or level = "" Or currentschool = "" Or currenttrack = "" Then
MessageBox.Show("Please enter the required fields!", "Registration", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
I have a datagridview where all the saved details in a text file are shown.
here's a screenshot of my datagridview:
WHAT I WANT TO DO: I want to retrieve the School name using the current school code (refer to the image) from the source text file(the one I used to populated my comboboxes). Instead of the school code, I want the School name to be shown in the datagridview.
Is there a possible way to do it?
I hope you guys understand what im trying to say.
Im new here.
Again just like I answered last time, use this function:
Function FetchSchoolName(schoolcode As String, filepath As String) As String
Dim filecontents = File.ReadAllLines(filepath)
For Each line As String In filecontents
If (line.Contains(schoolcode.Trim())) Then
Return line.Split("~"c)(1)
End If
Next
Return String.Empty
End Function
Example text entry:
sch001~abcinstitute
sch002~myacademy
sch003~someschoolname
Then pass the schoolcode(which you get from the datagridview) and filepath in the top-most function
MessageBox.Show(FetchSchoolName("sch002", "C:\Users\nobody\Desktop\somefile.txt"))
Output:
myacademy
Now in respect to your DataGridView, wherever you are filling(source binding) it use the above method
If you want to produce the same output as Nobody's answer but without looping, you can use LINQ, this also uses less lines of code but achieves the same output
Dim query = filecontents.Where(Function(x) x.Contains(schoolcode)).Select(Function(x) x.Split("~")(1)).FirstOrDefault
Return query.ToString()
Update 5/21/17. Thank you for the suggestion of using a Table. That was helpful. I actually figured it out. I made myinputable a global variable by declaring the Dim statement at the top and making it a Datagridview type. Now I can turn it off in the other event that I needed to do it.
I am a novice. I have created a Datagridview in VB 2015 to capture a bunch of data from the use. When the user is finished with the data entry, I want to store the cell values in my variables. I do not know how to capture any event from my dynamically created datagridview "myinputable." My code is below. Please help.
Private Sub inputmodel()
Dim prompt As String
Dim k As Integer
'
' first get the problem title and the number of objectives and alternatives
'
prompt = "Enter problem title: "
title = InputBox(prompt)
prompt = "Enter number of criteria: "
nobj = InputBox(prompt)
prompt = "Enter number of alternatives: "
nalt = InputBox(prompt)
'
' now create the table
'
Dim Myinputable As New DataGridView
Dim combocol As New DataGridViewComboBoxColumn
combocol.Items.AddRange("Increasing", "Decreaing", "Threashold")
For k = 1 To 6
If k <> 2 Then
Dim nc As New DataGridViewTextBoxColumn
nc.Name = ""
Myinputable.Columns.Add(nc)
Else
Myinputable.Columns.AddRange(combocol)
End If
Next k
' now add the rows and place the spreadsheet on the form
Myinputable.Rows.Add(nobj - 1)
Myinputable.Location = New Point(25, 50)
Myinputable.AutoSize = True
Me.Controls.Add(Myinputable)
FlowLayoutPanel1.Visible = True
Myinputable.Columns(0).Name = "Name"
Myinputable.Columns(0).HeaderText = "Name"
Myinputable.Columns(1).Name = "Type"
Myinputable.Columns(1).HeaderText = "Type"
Myinputable.Columns(2).Name = "LThresh"
Myinputable.Columns(2).HeaderText = "Lower Threshold"
'Myinputable.Columns(2).ValueType = co
Myinputable.Columns(3).Name = "UThresh"
Myinputable.Columns(3).HeaderText = "Upper Threshold"
Myinputable.Columns(4).Name = "ABMin"
Myinputable.Columns(4).HeaderText = "Abs. Minimum"
Myinputable.Columns(5).Name = "ABMax"
Myinputable.Columns(5).HeaderText = "Abs. Maximum "
Myinputable.Rows(0).Cells(0).Value = "Help"
If Myinputable.Capture = True Then
MsgBox(" damn ")
End If
End Sub
As #Plutonix suggests, you should start by creating a DataTable. Add columns of the appropriate types to the DataTable and then bind it to the grid, i.e. assign it to the DataSource of your grid, e.g.
Dim table As New DataTable
With table.Columns
.Add("ID", GetType(Integer))
.Add("Name", GetType(String))
End With
DataGridView1.DataSource = table
That will automatically add the appropriate columns to the grid if it doesn't already have any, or you can add the columns in the designer and set their DataPropertyName to tell them which DataColumn to bind to. As the user makes changes in the grid, the data will be automatically pushed to the underlying DataTable.
When you're done, you can access the data via the DataTable and even save the lot to a database with a single call to the Update method of a data adapter if you wish.
I know this is very basic, and I've done this hundreds of times. But, for some strange reason I am executing this command on a database, and it fails when it tries to read a column from the result. If I execute this statement in SQL Plus logged in as the same credentials, the row (table has 1 row) is selected just fine. Any ideas what I am doing wrong? I tried accessing the columns by name, by index, and indeed any column - all of them give no data. I tried without the .NextResult() (just in case), same exception.
'...
' Determine if this database is Multisite enabled
Dim multisiteCmd As OleDbCommand = DbConnection.CreateCommand
multisiteCmd.CommandText = "SELECT * FROM TDM_DB_VERSION;"
Dim dbVersionReader As OleDbDataReader = multisiteCmd.ExecuteReader()
If dbVersionReader.HasRows Then
dbVersionReader.NextResult()
'If a ReplicaID was generated for the Database ID, then this is part of a
'multisite implementation
'Dim dbRepID As String = dbVersionReader("DB_REPLICID")
Dim dbRepID As String = dbVersionReader(9)
PluginSettings.UseMultisite = False
If Not dbRepID Is Nothing Then
If dbRepID.Length > 0 Then
PluginSettings.UseMultisite = True
PluginSettings.MultisiteReplicaId = dbRepID
End If
End If
End If
dbVersionReader.Close()
As you can see from these Immediate commands, the connection is open:
? DbConnection.Provider
"OraOLEDB.Oracle"
? DbConnection.State
Open {1}
NextResult() is for statements that have more than one result set. For example, if you had sent a command like this:
"SELECT * FROM TDM_DB_VERSION;SELECT * FROM dual;"
Note there are two queries in there. You can handle them both with a single call to the database and a single OleDbDataReader, and NextResult() is part of how you do that.
What you want instead is this:
Dim multisiteCmd As OleDbCommand = DbConnection.CreateCommand
multisiteCmd.CommandText = "SELECT * FROM TDM_DB_VERSION;"
Dim dbVersionReader As OleDbDataReader = multisiteCmd.ExecuteReader()
If dbVersionReader.Read() Then
'If a ReplicaID was generated for the Database ID, then this is part of a
'multisite implementation
'Dim dbRepID As String = dbVersionReader("DB_REPLICID")
Dim dbRepID As String = dbVersionReader(9)
PluginSettings.UseMultisite = False
If Not dbRepID Is Nothing Then ' Do you mean check for DbNull here? "Nothing" is not the same thing
If dbRepID.Length > 0 Then
PluginSettings.UseMultisite = True
PluginSettings.MultisiteReplicaId = dbRepID
End If
End If
End If
dbVersionReader.Close()
This code returns zero rows count but there are 2 rows in appointment table.
The msgbox I commented was to check if the date is correct and format is correct and shows date as 2014/08/09. The appointment date in database is 2014/08/09 for 2 records (the only 2 records). Record count variable shows 0.
Table name (copied directly cut and paste) is Appointments and column is AppointmentDate.
The connectDatabase sub routine connects to the database successfully as I use it whenever I connect to database so it's correct as I connect to other tables correctly before I run this code using same sub routine.
Command.text contains
SELECT * FROM Appointments WHERE AppointmentDate = 2014/08/09
Don't know what other details to specify.
Private Sub frmAppointments_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'load appointments
LoadAppointments(dtpAppointmentDate.Value.Date)
End Sub
Public Sub LoadAppointments(whichdate As Date)
Dim sqlcmd As New OleDb.OleDbCommand
'set connection
ConnectDatabase()
With frmAppointments
'MsgBox(whichdate)
M_connDB.Open()
'fetch records from database
sqlcmd.Connection = M_connDB
sqlcmd.CommandText = "SELECT * FROM Appointments WHERE AppointmentDate = " & whichdate
.dataAdapterAppointments = New OleDb.OleDbDataAdapter(sqlcmd.CommandText, M_connDB)
'first clear data table to prevent duplicates
.dataTableAppointments.Rows.Clear()
.dataAdapterAppointments.Fill(.dataTableAppointments)
M_connDB.Close()
Dim rowindex As String
Dim iy As Long
Dim recordcount As Long
'check if any records exist
recordcount = .dataTableAppointments.Rows.Count
If Not recordcount = 0 Then
For iy = 0 To .dataTableAppointments.Rows.Count
For Each row As DataGridViewRow In .dtgrdAppointments.Rows
If row.Cells(0).Value = .dataTableAppointments.Rows(iy).Item(6) Then
rowindex = row.Index.ToString()
MsgBox(.dtgrdAppointments.Rows(rowindex).Cells(0).Value, vbInformation + vbOKOnly, "MSG")
Exit For
End If
Next
Next iy
Else
MsgBox("No Appointments for selected date.", vbInformation + vbOKOnly, "No Appoinments")
End If
End With
Use sql-parameters instead of string-concatenation. This should work in MS Access:
sqlcmd.CommandText = "SELECT * FROM Appointments WHERE AppointmentDate = ?"
sqlcmd.Parameters.AddWithValue("AppointmentDate", whichdate)
This prevents you from conversion or localization issues and -even more important- sql-injection.
2014/08/09 doesn't have quotes around it, making it a math expression (2014 divided by 8 divided by 9). Of course, your table has no rows with a date matching the result of that expression. But don't put in the quotes. Instead, add a parameter.
I don't VB, so I write it in C#. My point of view is it's better to specify the datatype too:
sqlcmd.CommandText = "SELECT * FROM Appointments WHERE AppointmentDate=#whichdate";
sqlcmd.Parameters.Add("#whichdate", SqlDbType.Date).Value = whichdate;