I am making a booking system application for a sports club. In my SQL Server database, I have two tables; one is named Memberships and the other is named Bookings.
Now, what I want is to allow a new booking for only those customers who have a membership. In the database I have joined both tables by the cust_id attribute where the Memberships table is parent and Bookings table is child. I want that when a new booking is tried, then it should first check if the customer ID is present in database. If it is present, then the booking should be allowed, otherwise not. But, my code shows an error first and then allows the booking
Here is my code for this:
Dim i As Integer
Dim str2 As String ' defines string variable for taking select query
str2 = "select Memberships.cust_id, booking_date, booking_time, booking_duration, game, poolno, courtno, tableno from Bookings, Memberships where Memberships.cust_id = Bookings.cust_id"
i = -1
Dim cmd2 As New SqlCommand(str2, con) 'defines a new sql command with str2 as query string and con as connection string
con.Open() 'sets the connection state to open
Dim bookchk As SqlDataReader = cmd2.ExecuteReader 'Defines and initiates the datareader to read data from database using cmd2 command
While bookchk.Read()
If Me.MskdTxtCustId.Text = bookchk("cust_id") Then
i = 1
End If
End While
bookchk.Close()
con.Close()
If i = -1 Then
MessageBox.Show("Error")
Exit Sub
End If
Why dont you just ask for the customers membership number before they can make a booking?
Otherwise you could make membership number a required field.
I could understand if you'd got as far as checking the database if it was a case of checking if the membership number they gave was valid, otherwise check for required data before connecting to a database.
Try this:
Dim sql As String
Dim customerIDyouWantToCheck As String
Dim i As Integer
i = 0
sql = "select cust_id from Memberships where Memberships.cust_id = '" & customerIDyouWantToCheck & "'"
Dim cmd2 As New SqlCommand(str2, con)
con.Open()
Dim bookchk As SqlDataReader = cmd2.ExecuteReader
If bookchk.HasRows() Then
i = 1
Else
i = -1
EndIf
I'm assuming you know the ID of the customer who you want to make a booking for. Otherwise I'm not sure what you're doing.
The best way to deal with anything like this is to ensure the database returns what you want first. Have you tried the run the query directly against sql-server?
What you really need is to check the customers ID in the Membership table first, and once the correct customer is established separately go ahead an insert into the Bookings table. These are both atomic transactions.
I think you are making this simply problem too complex.
Loading all booking/membership combinations and looping through them to find a certain customer ID is bad practice.
It is better to query for the desired customer ID directly. Plus, you should use SQL parameters instead of string concatenation to pass the customer ID to the query.
Before:
str2 = "select [...] where Memberships.cust_id = Bookings.cust_id"
i = -1
Dim cmd2 As New SqlCommand(str2, con)
After:
str2 = "select [...] where Memberships.cust_id = Bookings.cust_id and Bookings.cust_id = #CustomerID"
i = -1
Dim cmd2 As New SqlCommand(str2, con)
cmd2.Parameters.Add(New SqlParameter("#CustomerID", SqlDbType.Int).Value = Me.MskdTxtCustId.Text)
Regarding your actual problem:
but my code either shows error first and then allows the booking
As you didn't show the code that does the booking and how it is connected to the code you showed, we can't tell how you use the result from the code you posted to determine if the booking is done or not.
You should wrap the code that you posted in a method that returns true or false, depending whether the booking is allowed or not.
'the CustomerHasMembership() method contains the code you posted and
'returns true when the customer DOES have a membership
If CustomerHasMembership(Me.MskdTxtCustId.Text) Then
DoBooking()
End If
Related
I am trying to recover deleted rows by selecting rows in this picture, there are 3 records, so I deleted the 2
they will then show up here in the archive
but when I try to recover, instead of one by one, they will be recovered instantly. as it loads, the recovered records will then be back to the first picture]
which is the first 1 and this is my code for the recover:
Private Sub Recover_Click(sender As Object, e As EventArgs) Handles Recover.Click
Dim connString As String = ConfigurationManager.ConnectionStrings("dbx").ConnectionString
Using conn As New SqlConnection(connString)
Dim command As New SqlCommand("UPDATE [EmmeSubic].[dbo].[UserDetails] SET isDeleted = NULL where isDeleted = 1", conn)
' command.Parameters.Add("#user_id", SqlDbType.Int).Value = Driverlist.tbxUser_id.Text
conn.Open()
If MessageBox.Show("Are you sure you want to recover?", "Information", MessageBoxButtons.YesNo, MessageBoxIcon.Information) = DialogResult.Yes Then
command.ExecuteNonQuery()
For Each row As DataGridViewRow In DeletedUserTable.SelectedRows
DeletedUserTable.Rows.Remove(row)
Next
MessageBox.Show("The User is successfully Recovered!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information)
conn.Close()
End If
End Using
End Sub
UPDATE [EmmeSubic].[dbo].[UserDetails] SET isDeleted = NULL where isDeleted = 1 undeletes every record that was ever deleted. You need to also specify the according ID.
Your query has several other issues:
I personally would never include the database name in a query. Doing so prevents you from running your application against a test or integration database with different database name, which I always recommend to do - that way the database knows whether it is the production one or not even after copying the productional database over the test database. Why would the database care? There could be different behaviors in sending mails, different path definitions for imports and exports to other systems etc.).
Why is the deleted flag NULL when not set and not 0? In my humble opinion, it should be defined NOT NULL and be defaulting to 0.
I am converting my Access query to SQL view. One of the Access query has where condition where a user can input values
where table1.id=[Enter the ID of the user]
Is there a way to convert a query like this to T-SQL. It is important for me to leave the prompt as it is.
Well, first, there is little reason to convert to a pass-though query.
However, SQL Server cannot prompt you in access (or say a web site that uses SQL Server). So the GUI part must be created by YOUR web site, or say access client in this case.
It is usually best to build some prompt form with a button, since those automatic prompts that Access creates are VERY poor from a UI point of view.
As noted, it is VERY likely that you can just continue to use the access query.
However, if you need a pt query, then you use access code to ask/get the prompt value, and then add that to your query.
This will work:
Dim strSQL As String
Dim invoiceNum As String
strSQL = "select * from tblInvoices where invoiceNumber = "
invoiceNum = InputBox("enter Invoice Number")
If invoiceNum = "" Then Exit Sub
strSQL = strSQL & invoicenumber
With CurrentDb.QueryDefs("qryPassR")
.SQL = strSQL
End With
' now, docmd.OpenReport, or openform or
' whatever it is you wanted to do with the sql
However, as noted, for reports etc., I would build a nice form that allows the user to enter a value. The query prompts are pure torture to your users, and they are not user friendly at all.
Also, the above assumes that you going to open some report, or some such. If you need the data returned in a reocrdset, the use this:
Dim strSQL As String
Dim invoiceNum As String
dim rst As DAO.RecordSet
strSQL = "select * from tblInvoices where invoiceNumber = "
invoiceNum = InputBox("enter Invoice Number")
If invoiceNum = "" Then Exit Sub
strSQL = strSQL & invoicenumber
With CurrentDb.QueryDefs("qryPassR")
.SQL = strSQL
Set rst = .OpenRecordset
End With
And last but not least, as others suggested here, you should consider a stored procedure with parameters, as the above is subject to SQL injection.
I had confusion with my code:
Dim sqladapter As SqlDataAdapter = New SqlDataAdapter()
Dim sqlcmd As SqlCommand = New SqlCommand()
sqlcmd = New SqlCommand("SELECT login, pass from Table1 where login=" & login.Text & "and pass='" & password.Text.ToString() & "';", connect)
Dim dr As SqlDataReader = sqlcmd.ExecuteReader()
Dim dt As DataTable = New DataTable()
dt.Load(dr)
If (dt.Rows.Count = 1) Then
'Display welcome page or do some action here.
Now, my question is, is there any other way of doing Rows.Count==1 . I'm feeling that it is very wrong and makes no sense at.
How do you verify from database that a user has only one valid record in table other than counting rows.
Thanks in Advance :)
(Please ask me before reporting question)
You have two problems, one is called Sql Injection and you have already numerous links that explain why is really bad. Another one is the plain text password stored in your database. This is a big security concern because everyone that has the possibility to look at your database could see the passwords of your users. (The gravity of this, of course, is linked to the nature of your application but cannot be downplayed) See this link for an answer on how to hash a string (a password) and get its encrypted version to store in the database instead of the plain text.
Finally the code you use could be changed to avoid both the SqlDataAdapter and the DataTable.
Just use an ExecuteScalar against an IF EXIST query that return just 1 if the user/password exists or zero if not
Dim cmdText = "IF EXISTS(SELECT 1 FROM Table1 WHERE login = #log AND pass = #pwd) " & _
"SELECT 1 ELSE SELECT 0"
using connect = new SqlConnection(connectionstring)
using sqlcmd = New SqlCommand(cmdText, connect)
connect.Open()
sqlcmd.Parameters.AddWithValue("#log", login.Text)
sqlcmd.Parameters.AddWithValue("#pwd", password.Text) ' <- Subst with a call to an hash function
Dim exists = Convert.ToInt32(sqlcmd.ExecuteScalar())
if exists = 1 Then
'Display welcome page or do some action
else
end if
End Using
End Using
There is only one way to answer to the question and its to count rows. The different solution would be to count them in database. For example you could write stored procedure that takes username and password and returns boolean this way you would drag less data.
As a side note there is potential sql injection in your code. You should not store clear password in database. You should return the whole row and match hash of the password from database to the hash of the paasword that you get from UI.
I am using a VB program connected to an access database. In my code, I want to check if a record exists at the specified row, and if not, do something. Checking if the row exists is my issue. In pseudocode, this is what I want to achieve:
If RecordAtLocationExists = False Then
...
End If
Code I have tried includes:
If DBDataSet.Tables(TableName).Rows(QuestionNumber).IsNull = True Then
If DBDataSet.Tables(TableName).Rows(QuestionNumber) = "" Then
If DBDataSet.Tables(TableName).Rows(QuestionNumber) = Nothing Then
If DBDataSet.Tables(TableName).Rows(QuestionNumber) = Null Then
None of the above code works. I have tried to search for a solution, but everything else seems far too complicated for this. I am probably approaching this wrong, but hopefully it makes sense what I am trying to achieve.
Any ideas?
First of all, you are trying to check if the record exists at a DataTable, not at database. Database data could have changed since you filled your DataTable. Try to query the database directly:
Dim specificRow as Integer = 23 '<-- Set this variable to the specific row you are looking for
Dim query As String = "SELECT * FROM TableName WHERE QuestionNumber = ?"
Dim cmd As OleDbCommand = New OleDbCommand(query, myConnection)
cmd.Parameters.AddWithValue("questionnumber", specificRow)
dr = cmd.ExecuteReader
And test if the command return rows
If dr.Read() Then
' Do stuff here
Else
' Do another stuff here
End if
Dim sqlCountQuery As String = "SELECT COUNT(*) FROM codes"
Dim SQLConnection As MySqlConnection = New MySqlConnection
Dim CountCommand As New MySqlCommand(sqlCountQuery, SQLConnection)
SQLConnection.ConnectionString = strServerString
SQLConnection.Open()
reader = CountCommand.ExecuteReader
reader.Read()
CodeCounter = reader.GetInt32(0)
SQLConnection.Close()
Dim sqlQuery As String = "SELECT * FROM codes"
Dim Command As New MySqlCommand(sqlQuery, SQLConnection)
SQLConnection.Open()
reader = Command.ExecuteReader()
reader.Read()
For b = 0 To CodeCounter - 1
test = reader.GetInt32(b)
Next
The top bit of code retrieves the number of codes currently stored in the database but when I move on to the second part with the for loop, it correctly retrieves the first code from the database, but after that I get an error saying "You have specified an invalid column ordinal.". I have been running it line by line which is how I know it retrieves the first code correctly.
You mixed up the number of columns to the number of rows. CodeCounter is the row count but in second part of code you tried to get data from column. reader.GetInt32(int) gets data from given column.
All code written in a very bad. Examin this article with example for information how to use DataReader. Article for SQL Server data provider but it can be helpful for you.