Good evening,
I'm using the following code to truncate a table in my MySQL database. From what I can tell, the query is running fine and the tables are being truncated. However, the if statement that I'm using to test if rows are affected is being evaluated on the Else statement.
So how come the table in the database is being truncated - as expected - but the Else statement is being evaluated - as if no rows are affected? What am I doing wrong?
HERE'S THE CODE:
Public Sub purgeCC()
Dim dbAdapter As New MySqlDataAdapter
Dim dbCmd As New MySqlCommand
Dim ConnectionString As String = String.Format("Server={0};Port={1};Uid={2};Password={3};Database=accounting", FormLogin.ComboBoxServerIP.SelectedItem, My.Settings.DB_Port, My.Settings.DB_UserID, My.Settings.DB_Password)
Dim myQuery As String = "TRUNCATE TABLE cc_master"
Using dbConn As New MySqlConnection(ConnectionString)
Using dbComm As New MySqlCommand()
With dbComm
.Connection = dbConn
.CommandType = CommandType.Text
.CommandText = myQuery
End With
Try
Dim affectedRow As Integer
dbConn.Open()
affectedRow = dbComm.ExecuteNonQuery()
If affectedRow > 0 Then
MsgBox("Credit Card Master table has been successfully purged!", MsgBoxStyle.Information, "DATABASE PURGED!")
Else
MsgBox("Credit Card Master table was not purged!", MsgBoxStyle.Critical, "ATTENTION")
End If
Catch ex As Exception
MessageBox.Show("A DATABASE ERROR HAS OCCURED" & vbCrLf & vbCrLf & ex.Message & vbCrLf & _
vbCrLf + "Please report this to the IT/Systems Helpdesk at Ext 131.")
End Try
dbConn.Close()
dbComm.Dispose()
End Using
End Using
End Sub
Per this document http://dev.mysql.com/doc/refman/5.0/en/truncate-table.html
the truncate command may not always return the rows affected if the DB version is greater than 5.somthing and the table does not have foreign key constraints. if you do have FKs then a delete is processed for each row and you get the return value you are seeking, but if you don't then mysql will drop and re-add the table (which is much faster), which means it has no ideas how many records were affected.
Your if statement is being evaluated correctly, it's just that affectedRow (which should probably be affectedRows by the way, but I'm just being pedantic there) is not being set as you expect.
It's not wise to depend on the affected rows count for a truncation as per the online docs for truncate table.
In some cases, it's only accurate if it gets mapped to a delete (such as specific versions with the InnoDB engine where there are foreign key constraints, since they have to be checked or cascaded).
With other engines, you may get 0 because it drops the table and then recreates it.
If you really want the information, execute a select count(*) before and after the truncation. The after should usually be zero, of course (unless the truncation fails).
Related
I've been using the code below to populate tables in a MySQL database for a few years and it's been working fine.
Imports MySql.Data.MySqlClient
Public sub Thing(dt as datatable)
Try
'dt is datatable object populated from MSsqlServer
Dim MySQLcmdSelect As MySqlCommand = New MySqlCommand("Select * From " & tableName) With {
.Connection = MySQLcnn
}
Dim MySQLad As New MySqlDataAdapter(MySQLcmdSelect)
Dim MySQLcmdBuilder As New MySqlCommandBuilder(MySQLad)
Dim MySQLcmd As MySqlCommand = MySQLcmdBuilder.GetInsertCommand()
MySQLcmd.Connection = MySQLcnn
MySQLad.InsertCommand = MySQLcmd
MySQLad.Update(dt)
Catch ex As Exception
Debug.Print(ex.Message)
Console.WriteLine("Error when populating " + tableName + ": " + ex.Message + vbCrLf + ex.InnerException.ToString)
WriteLog(ex.Message)
End Try
End Sub
The problem is, it's stopped working!
The connector seems to be working ok as I can drop tables and create them, but this will not let me bulk insert the contents of the datatable 'dt' into the MySQL table.
It doesn't throw an exception, it just passes over the .update(dt) line as if it were a Debug.Print() line when there's 1000s of rows in dt.
Effectively I'm selectively extracting data from tables in MS SQLserver and bulk uploading them to tables with the same name in MySQL.
a) is this the best way to do it, and
b) why has this suddenly stopped working?
According to phpMyAdmin its Server version: 5.6.51 - MySQL Community Server (GPL)
EDIT: Further info... all the SQL commands to drop existing tables and create tables work. It is only the .update(dt) that doesn't work.
Possible problems with your code could be that the schemas do not match exactly, auto increment columns, or the connection could have been disposed elsewhere (it should be declared local to the method where it is used). Another problem is that dt has had AcceptChanges called or LoadOptions were set incorrectly.
Private ConnStr As String = "Your connection string"
Public Sub Thing(dt As DataTable, tableName As String)
'check the datatable - if it is ok then this check is probably not necessary
Dim changesDT = dt.GetChanges()
If changesDT.Rows.Count < 1 Then
MessageBox.Show("No changes to update")
Exit Sub
End If
Using cn As New MySqlConnection(ConnStr),
MySQLad As New MySqlDataAdapter("Select * From " & tableName, cn)
cn.open() ' added by OP
Dim MySQLcmdBuilder As New MySqlCommandBuilder(MySQLad)
MySQLad.Update(dt)
End Using
End Sub
Perhaps you have "0000-00-00"? If so, a setting has changed the default -- new versions of MySQL disallow zero dates. Read about sql_modes.
Still can't get the bulk upload to work, but we have redesigned this so that data is inserted into MySQL at the same time we store it in the MS-SQL database and have removed the need to bulk upload.
I have got a datagrid view which is filled by a table on my microsoft mysql database my problem is i need to select a row and its values then appear in the text boxes which i have solved. but now if any changes are to occur i want to create an update function to update the records with the changes made. I've tried but failed until now.
Public Sub AddMember(FirstName As String, Surname As String, Admin As Integer)
Try
Dim strInsert As String = _
"UPDATE test Firstname='this should be the value entered in the text box' " & _
"WHERE Firstname = 'this should equal to the value selected from the datagrid view'"
MsgBox(strInsert)
SQLCon.Open()
SQLCmd = New SqlCommand(strInsert, SQLCon)
SQLCmd.ExecuteNonQuery()
SQLCon.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
I you are working with MySQL then you should be using MySqlCommand instead of SqlCommand. Also use a MySqlConnection. You find both in the MySql.Data.MySqlClient namespace.
You also will need to download and install the "Connector/Net" and add a reference to MySql.Data.dll in your project if you have not done this already .
Also use command parameters instead of string concatenation. This is both safer (See: SQL injection) and easier, as you do not have to worry about formatting strings, numbers and dates the right way for SQL.
Dim sql As String = "UPDATE tst SET FirstName=#fn, Surname=#sn WHERE Id=#id"
Using conn = New MySqlConnection(connectionString)
Using cmd = New MySqlCommand(sql, conn)
cmd.Parameters.AddWithValue("#fn", FirstName)
cmd.Parameters.AddWithValue("#sn", Surname)
cmd.Parameters.AddWithValue("#id", id)
conn.Open()
cmd.ExecuteNonQuery()
End Using
End Using
Note that the WHERE-clause should identify the database row by its primary key. In MySQL a primary key is best created as AUTO_INCREMENT column. In no case use the first name in order to identify the row, as serveral persons can have the same first name. See: Using Primary Keys and SQL PRIMARY KEY Constraint.
check syntax for update here
so change your query as follows:
Dim strInsert As String = " update test Set FirstName= '" & FirstName & "'," & _
"Surname='" & Surname & "'," & _
"admin='" & Admin & "')"
This is the query you should use.
Parameters with # are actually values you're sending to SQL.
Update test Set FirstName=#FirstName where Id=#Id
I cannot seem to find the answer to my problem anywhere on the internet. I have seen solutions for others such as adding keys to appsettings etc, none of which have worked for me.
Imports Oracle.DataAccess.Client
Imports Oracle.DataAccess.Types
Imports System.Data
Sub Button1Click(sender As Object, e As EventArgs)
Dim oradb As String = "DATA SOURCE=INITIATE;PASSWORD=pASS;PERSIST SECURITY INFO=True;USER ID=uSER"
Dim conn As New OracleConnection(oradb)
Try
Dim sql As String = "select MEMRECNO from INIT.MPI_MEMHEAD where MEMIDNUM = '" + txtMRN.Text + "'"
Dim cmd As New OracleCommand(sql, conn)
cmd.CommandType = CommandType.Text
Dim dr As OracleDataReader = cmd.ExecuteReader()
dr.Read()
txt1.Text = dr.GetInt32(0)
Catch ex As Exception
richTextBox1.Text = richTextBox1.Text + vbCrLf + ex.Message
End Try
End Sub
Now, when I run this code, if I enter a value in the top 25 records (when visually looking at the table in Oracle) it returns the result. However, when I enter a value that might be record number 1 million, i get this error: "Operation is not valid due to the current state of the object."
Yes, the value does exist. Because if I run the exact same query in Oracle, I get the result.
This leads me to believe that the connection is timing out, closing, or there is a limit on how many rows can be returned using the Oracle Data Access Client.
I have an ado created recordset in access 2010 it returns 9 different fields from a stored procedure on sql server 2008 r2.
I am trying to use this recordset (which does populate) to insert all of the records into a table that matches the output. My issue is that two of the fields are name fields that have commas in them. For example Smith, Joseph-- I need to insert that comma into the appropriate field. Right now it throws an error because of the comma in the field.
Here is the code that I am using:
Option Compare Database
'Executes the filtering routine
Private Sub cmdApplyFilter_Click()
'If txtStartDate.Value And txtEndDate.Value Is Not Null Then
' QuickFilter
'Else
' DefaultRun
'End If
QuickFilter
'********** Filter as you type **********
'Private Sub txtFilter_Change()
' QuickFilter
'End Sub
End Sub
'Perform the actual filtering on the subform
Private Sub QuickFilter()
Dim Sql As String
Dim filter As String
If txtStartDate = vbNullString Then
'Reset the filter if the textbox is empty
'This will be the default sql statement to fill the subreport
SubForm.Form.FilterOn = False
Else
'Some common substitutions that users may have already inserted as wildchars
filter = Replace(txtStartDate, "%", "*")
filter = Replace("*" & filter & "*", "**", "*")
'Construct the filter for the sql statement
'/*********** GROUP BY GOES HERE ***********/
'Assign the filter to the subform
'SubForm.Form.filter = Sql
'SubFomr.Form.FilterOn = True
End If
End Sub
Private Sub Form_Load()
'Sets up the connection with the sql server database retrieves the stored procedure, executes it and puts the result set into a table
Dim Conn As ADODB.Connection
Dim Cmd As ADODB.Command
Dim Rs As ADODB.Recordset
Dim rs1 As ADODB.Recordset
Dim Connect As String
Dim filter As String
Connect = "Provider =SQLNCLI10; Data Source=10.50.50.140; Initial Catalog=CCVG; User Id = oe; Password = Orth03c0; "
'Establish the connection with sql server
Set Conn = New ADODB.Connection
Conn.ConnectionString = Connect
Conn.Open
'Open the recorset
Set Cmd = New ADODB.Command
Cmd.ActiveConnection = Conn
Cmd.CommandText = "dbo.cusGenNoNotesReport"
Cmd.CommandType = adCmdStoredProc
Set Rs = Cmd.Execute()
Dim x As Integer
If Not Rs.BOF And Not Rs.EOF Then
If Not Rs.BOF Then Rs.MoveFirst
Do Until Rs.EOF
For x = 0 To Rs.Fields.Count - 1
MsgBox Rs.Fields(x)
'DoCmd.RunSQL "INSERT INTO tblNoNotes (Provider, Facility, TicketNumber, Charges, FinancialClass, CPT, CPTDescription, PatientFullName, DateOfEntry) SELECT " & Rs.Fields(x).Value & ""
Next x
Rs.MoveNext
Loop
End If
'Process results from recordset, then close it.
'DoCmd.RunSQL "INSERT INTO tblNoNotes (Provider, Facility, TicketNumber, Charges, FinancialClass, CPT, CPTDescription, PatientFullName, DateOfEntry) VALUES (""" & Rs![Provider] & """,""" & Rs![Facility] & """ & Rs![TicketNumber] & """, """ & Rs![Charges] & """, """ & Rs![FinancialClass] & """, """ & Rs![CPT] & """, """ & Rs![CPTDescription] & """, """ & Rs![PatientFullName] & """, """ & Rs![DateOfEntry] & """ )"
Rs.Open
Rs.Close
Conn.Close
Set Rs = Nothing
Set Cmd = Nothing
Set Conn = Nothing
End Sub
You have an ADO Recordset, Rs, which contains data you want to add to your Access table. Instead of trying to fix the INSERT statement to add each row, it should be easier to open a DAO Recordset for the destination table and store the values from each ADO row by adding a new row the the DAO Recordset. Although this is still a RBAR (row by agonizing row) approach, it should be significantly faster than building and executing an INSERT statement for each row.
First of all, make sure to add Option Explicit to your module's Declarations section.
Option Compare Database
Option Explicit
Then use this code to append the ADO Recordset data to your table.
Dim db As DAO.Database
Dim rsDao As DAO.Recordset
Set db = CurrentDb
Set rsDao = db.OpenRecordset("tblNoNotes", _
dbOpenTable, dbAppendOnly + dbFailOnError)
Do While Not Rs.EOF
rsDao.AddNew
rsDao!Provider.Value = Rs!Provider.Value
rsDao!Facility.Value = Rs!Facility.Value
rsDao!TicketNumber.Value = Rs!TicketNumber.Value
rsDao!Charges.Value = Rs!Charges.Value
rsDao!FinancialClass.Value = Rs!FinancialClass.Value
rsDao!CPT.Value = Rs!CPT.Value
rsDao!CPTDescription.Value = Rs!CPTDescription.Value
rsDao!PatientFullName.Value = Rs!PatientFullName.Value
rsDao!DateOfEntry.Value = Rs!DateOfEntry.Value
rsDao.Update
Rs.MoveNext
Loop
rsDao.Close
Set rsDao = Nothing
Set db = Nothing
Note this approach means you needn't worry about whether PatientFullName contains a comma, or apostrophe ... or struggle with properly quoting field values to produce a valid INSERT statement. You simply store the value from one recordset field to the appropriate field in another recordset.
I think the real problem you're complaining about here is that your data in the ADO Recordset has quotes (sometimes called apostrophes) in it. Anytime quotes could possibly exist in your data you will need to check for and escape them before using the data in an SQL Statement. You will need to know this not only for inserts but also for performing filtering and creating WHERE statements as well. For example:
Replace(Rs![PatientFullName], "'", "''")
A simpler way to do this is to make your own little function. The "PQ" stands for pad quotes. You can name it whatever you want.
PQ(rs![PatientFullName])
Public Function PQ(s as String) as String
PQ = Replace(s, "'", "''")
End Function
But I also agree with HansUp that it's much easier to use recordsets for inserts. I basically never use SQL Insert statements anymore, except for places where I have no option such as SQL Server T-SQL.
Be aware that if you do want to use insert statements, you should consider using the following:
CurrentDb.Execute "INSERT INTO Statement Goes Here", dbFailOnError
This is considered to be a more robust solution than DoCmd.RunSQL, mostly because it runs in the context of the underlying Database Engine instead of the Access interface. Using CurrentDb.Execute prevents you from having to use DoCmd.SetWarning statements to turn off warnings.
Why won't this delete the data in my MySQL database!?
Private Sub Button4_Click(sender As System.Object, e As System.EventArgs) Handles Button4.Click
Dim dbCon As MySqlConnection
Dim strQuery As String = ""
Dim SQLCmd As MySqlCommand
Dim DR As MySqlDataReader
Try
dbCon = New MySqlConnection("Server=Localhost;Database=myusers;Uid=root;Pwd=Mypassword")
strQuery = "DELETE settings FROM settings WHERE user=" & Me.loginuser.Text
'* FROM settings WHERE user = "Testuser"'
SQLCmd = New MySqlCommand(strQuery, dbCon)
' OPEN THE DB AND KICKOFF THE QUERY
dbCon.Open()
DR = SQLCmd.ExecuteReader
While DR.Read
req1.Text = "" And exlink.Text = ""
End While
' DONE! Close DB
DR.Close()
dbCon.Close()
Catch ex As Exception
TextBox8.Text = ("Fail" & vbCrLf & vbCrLf & ex.Message)
End Try
Here is a picture of my database:
Alternatively I could somehow make it replace what is already in the database, in which case please help me with that.
Try
strQuery = "DELETE FROM settings " _
& " WHERE user = '" & Me.loginuser.Text & "'"
but as was stated earlier, you should be using parameterized queries. If you had a user named O'Brien then your query (as composed above) would fail because of the embedded single quote. When you use DELETE, you are deleting entire records and you already specify the table name in the FROM clause.
I will try to change your code in this way
Using con = New MySqlConnection("Server=.....")
con.Open()
Dim sqlText = "DELETE * FROM settings WHERE user = #ulogin"
Using cmd = new MySqlCommand(sqlText, con)
cmd.Parameters.AddWithValue("#ulogin", Me.loginuser.Text)
cmd.ExecuteNonQuery()
End Using
End Using
First and foremost, do not use string concatenation to create command texts to pass to the database engine. In that way you risk Sql Injections, also, if the user name contains a single quote (i.e. O'Hara) your code will fail with a syntax error (Same problems arise for date formatting, parsing numeric decimals and other globalization issues). Instead a parametrized query like the one in code above will avoid all of these problems.
In a parametrized query, the text of the query doesn't contains the actual value for the search condition or the update or insert data. Instead it contains placeholders ( in our case it is called #ulogin). The correct value to insert at the placeholders position is specified using one or more MySqlParameter added to the Parameters collection of the MySqlCommand. In this case I have used the AddWithValue method that derives the correct datatype directly from the datatype of the value. Because Me.loginuser.Text is a string value then the parameter will be treated as a string value replacing incorrect single quotes and removing extraneus characters usually used to Mount Sql Injections Attacks. The engine will do the rest inserting the correct value at the placeholder at execution time
EDIT: Seeing your comment about the MySql connector used, I will try to update my answer to show a semi-equivalent version for NET 1.
Try
Dim con As MySqlConnection = New MySqlConnection("Server=.....")
con.Open()
Dim sqlText as String = "DELETE * FROM settings WHERE user = #ulogin"
Dim cmd As MySqlCommand = new MySqlCommand(sqlText, con)
Dim par As MySqlParameter = New MySqlParameter("#ulogin", MySqlDbType.VarChar)
par.Value = Me.loginuser.Text
cmd.Parameters.Add(par)
cmd.ExecuteNonQuery()
Finally
con.Close()
End Try
I am not sure if the connector 1.0.10 supports the parameter name with the # prefix or just the : prefix
i dont think you can use double quotes in mysql, i think its single quotes only. try
Query = "DELETE * FROM settings WHERE user = '" & Me.loginuser.Text & "'"