I don't know how to find if the where statement occurred in the code when I execute it:
Dim cmd2 As SqlCommand = New SqlCommand("
UPDATE ShTb
SET Email=#EmailAddress,
Temp=#temp,
TEL=#telnum,
TempTime=#temptime
WHERE ShID=#SharjID", con1)
cmd2.Parameters.AddWithValue("#EmailAddress", EmailAddress)
cmd2.Parameters.AddWithValue("#SharjID", SharjID)
cmd2.Parameters.AddWithValue("#temp", temp)
cmd2.Parameters.AddWithValue("#telnum", telnum)
cmd2.Parameters.AddWithValue("#temptime", temptime)
con1.Open()
cmd2.ExecuteNonQuery()
con1.Close()
I assume you want to know if any rows were effected by the update.
You can do this by checking the return value of ExecuteNonQuery
Dim rowsEffected = cmd2.ExecuteNonQuery()
if rowsEffected > 0 Then
'One or more rows were changed
End if
ExecuteNonQuery returns the number of rows affected by the command.
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. (MSDN)
dim r1 as int
r1=cmd2.ExecuteNonQuery()
If r1 > 0 --one, or more rows were affected....
Related
I have a customer that wants to import his sub-customers pricetools (more that 2.000.000 records) every day into a SQL Server database (and yeah....there are more than 900.000 rows of changes every day).
The data is provided in CSV format (not in RFC-4180 standard ç_ç, but nvm) and can be an Insert, Delete or Update of data.
My problem is that the insert of the data inside the database take more than 1 night to end and I need to speed it up.
What I'm doing at the moment is:
Cast the csv file into a Datatable (Tab1) (~3 minutes)
Select all data inside the previous table (Tab0) and match them with the Tab1 (~15 minutes, the unchanged rows are flagged as unmodified, so they are ignored in the adapter.Update, I check that thing for the first rows and seems that it works, I use dataRowToProcess.AcceptChanges() to achieve that).
Launch the following command to apply the changes (More than 5 hours for 900.000 changes):
cmdSQL = New SqlCommand(superQuery, cn)
Dim adapter As SqlDataAdapter = New SqlDataAdapter(cmdSQL)
adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
Dim build As SqlCommandBuilder = New SqlCommandBuilder(adapter)
build.SetAllValues = False
adapter.Update(dataTableCustomersDetail) 'Insert/Update records
If I have many inserts the process, it is slower than the same amount of updates.
What am I doing wrong? Am I missing some SqlDataAdapter option?
Thanks
Thanks to #matsnow i figuredOut a solution with SqlBulkCopy. Considering that half of the table change everitime and that is a static anag i decide that a Delete/Insert of the data is the fastest way to follow (Now it takes 5-6 Minutes instead of 10).
Code:
'Delete all table content
Dim cmd As SqlCommand = New SqlCommand("TRUNCATE TABLE " + tableName, cn)
cmd.ExecuteNonQuery()
'Insert all records
Using sbc As SqlBulkCopy = New SqlBulkCopy(cn)
sbc.DestinationTableName = tableName
sbc.BulkCopyTimeout = 1000
For Each column As DataColumn In dataTableCustomersDetail.Columns
sbc.ColumnMappings.Add(column.ToString(), column.ToString())
Next
sbc.WriteToServer(dataTableCustomersDetail)
End Using
Use Connection.BeginTransaction() to speed up the DataAdapter update.
cn.Open() 'open connection
Dim myTrans As SQLTransaction
myTrans = cn.BeginTransaction()
'Associate the transaction with the select command object of the DataAdapter
adapter.SelectCommand.Transaction = myTrans
adapter.Update(dataTableCustomersDetail) 'do the update as before
Try
myTrans.Commit()
Catch ex As Exception
myTrans.Rollback()
End Try
cn.Close()
With 8000 rows this changes the update time from over 5 minutes to 2 seconds
net and would to have the Header Text of columns in a datagridview be named after results from the database, e.g the query in my code returns four dates,30/08/2017,04/09/2017,21/09/2017 and 03/02/2018. My aim is to have the column headers in the data grid named after those dates. Your help will highly be appreciated.
sql = "SELECT COUNT (ServiceDate) As NoOfServiceDates FROM (SELECT DISTINCT ServiceDate FROM tblattendance)"
Using command = New OleDbCommand(sql, connection)
Using reader = command.ExecuteReader
reader.Read()
ColumnNo = CInt(reader("NoOfServiceDates")).ToString
End Using
End Using
DataGridView1.ColumnCount = ColumnNo
For i = 0 To DataGridView1.Columns.Count - 1
sql = "SELECT DISTINCT ServiceDate FROM tblattendance"
Using command = New OleDbCommand(sql, connection)
Using reader = command.ExecuteReader
While reader.Read
DataGridView1.Columns(i).HeaderText = reader("ServiceDate").ToString
End While
End Using
End Using
Next
The current code re-runs the query each time through the column count loop, meaning it will set the column header for that column to all of the date values in sequence, so the last value in the query shows in the all the columns. You only need to run the query once:
Dim i As Integer = 0
sql = "SELECT DISTINCT ServiceDate FROM tblattendance"
Using command As New OleDbCommand(sql, connection), _
reader As OleDbDatareader = command.ExecuteReader()
While reader.Read
DataGridView1.Columns(i).HeaderText = reader("ServiceDate").ToString
i+= 1
End While
End Using
Additionally, this still results in two separate trips to the database, where you go once to get the count and again to get the values. Not only is this very bad for performance, it leaves you open to a bug where another user changes your data from one query to the next.
There are several ways you can get this down to one trip to the database: loading the results into memory via a List or DataTable, changing the SQL to include the count and the values together, or adding a new column each time through the list. Here's an example using the last option:
DataGridView1.Columns.Clear()
Dim sql As String = "SELECT DISTINCT ServiceDate FROM tblattendance"
Using connection As New OleDbConnection("string here"), _
command As New OleDbCommand(sql, connection)
connection.Open()
Using reader As OleDbDataReader = command.ExecuteReader()
While reader.Read
Dim column As String = reader("ServiceDate").ToString()
DataGridView1.Columns.Add(column, column)
End While
End Using
End Using
Even better if you can use something like Sql Server's PIVOT keyword in combination with the DataGridView's AutoGenerateColumns feature for DataBinding, where you will write ONE SQL statement that has both column info and data, and simply bind the result set to the grid.
The For Next is incorrect. You execute your command for every column, when you only need to execute it once. The last result from the DataReader will be the header for every column as currently written.
You should iterate through your DataReader and increment the cursor variable there:
Dim i As Integer = 0
Using command = New OleDbCommand(sql, connection)
Using reader = command.ExecuteReader
While reader.Read
DataGridView1.Columns(i).HeaderText = reader("ServiceDate").ToString
i += 1
End While
End Using
End Using
I have table and i want to set value if cell=null then set record by textbox .
here is my table
--------------------
col1| col2| Note
1 2 aaa
5 5 (*) set record Only here if cell is Null
42 14
47 55
------------------
here is my code and my problem is the query write for every cell that is Null and I want to write only for next cell that before it is not null
con.Open()
query = " update firealarm set Note=#Note where Note Is Null"
Dim command As SqlCommand = New SqlCommand(query, con)
command.Parameters.Add(New SqlParameter("#Note", SqlDbType.NVarChar))
command.Parameters("#Note").Value = Notebox.Text.ToString
command.ExecuteNonQuery()
con.Close()
First, let's fix the immediate problem: in SQL NULL is not equal to anything, including other NULLs, so Note<>Null is true for all rows. To address this problem, SQL has special operators IS NULL and IS NOT NULL. Using where Note is not NULL will fix the problem.
A bigger problem remains, though: your program is vulnerable to SQL Injection attack. To fix this problem in Visual Basic see this Q&A.
Edit: (in response to an edit of the question)
I want to write only for next cell that before it is not null
The "next cell" implies some order of cells in the table. Since table rows should be treated as an unordered collection, let's assume that you would like to order by col1, the way the data is ordered in your example.
The query condition becomes much bigger for this:
UPDATE f
SET f.Note=#Note
FROM firealarm f
WHERE Note Is Null
AND NOT EXIST (
SELECT * FROM firealarm ff WHERE ff.col1 < f.col1 AND ff.Note IS NULL
)
The new WHERE condition says that the update needs to be done on the cell with the lowest col1 and NULL value in the Note column.
For updating exact row you need more conditions in the WHERE statement
UPDATE firealarm SET Note=#Note
WHERE Note IS NULL
AND Col1 = #ValueOfCol1
AND Col2 = #ValueOfCol2
vb.net code
con.Open()
Dim query As String = <![CDATA[UPDATE firealarm SET Note=#Note
WHERE Note IS NULL
AND Col1 = #ValueOfCol1
AND Col2 = #ValueOfCol2]]>.Value
Dim command As SqlCommand = New SqlCommand(query, con)
With command.Parameters
.Add(New SqlParameter With {.ParameterName = "#Note",
.SqlDbType = SqlDbType.NVarChar,
.Value = Notebox.Text})
.Add(New SqlParameter With {.ParameterName = "#ValueOfCol1",
.SqlDbType = SqlDbType.Int,
.Value = 5})
.Add(New SqlParameter With {.ParameterName = "#ValueOfCol2",
.SqlDbType = SqlDbType.Int,
.Value = 5})
End With
command.ExecuteNonQuery()
con.Close()
Or use value of identity column if your table have this
Try this query,it will update just first row which is null
WITH UpdateList_view AS
( SELECT TOP 1 * from Fire alarm
Where NOTE is Null )
update UpdateList_view
set Note=#Note
When I run the following SQL statement in SQL Server Management Studio it returns a count of 2
SELECT COUNT(*)
FROM Daisy_Copy2
WHERE ChargeCode = '1';
But for some reason when I run the following VB.net code the result variable returns a 0 and doesn't identify that duplicate codes exist.
Dim result As Integer
Using cmdb = New SqlCommand("SELECT COUNT(*) FROM Daisy_Copy2 WHERE ChargeCode = '1'", conn)
Int(result = cmdb.ExecuteScalar())
If result > 1 Then
MessageBox.Show("Duplicate Codes Exist!", "Billing", _
MessageBoxButtons.OK, MessageBoxIcon.Information)
Else
MsgBox(result)
End If
End Using
Can anyone help me understand why?
Any help greatly appreciated.
Instead of ExecuteNonQuery you should use ExecuteScalar
Dim result As Integer = CInt(cmd.ExecuteScalar())
ExecuteNonQuery is normally used for updates or inserts that don't leave a result, so it returns an integer telling you how many rows were affected, not the result itself.
What you most likely are meaning to use is ExecuteScalar which returns the first column of the first row in the result set returned by the query, in this case the integer containing your count.
this is just a way you can use:
Dim Sqlda = New SqlDataAdapter("SELECT COUNT(*) AS tCount FROM Daisy_Copy2 WHERE ChargeCode=1", conn)
Dim sqlds = New DataSet
Sqlda.Fill(sqlds, "Daisy_Copy2")
Dim tblRow As DataRow
For Each tblRow In sqlds.Tables("Daisy_Copy2").Rows
MsgBox(tblRow("tCount").ToString())
Next
use below link to read more about it
System.Data.SqlClient Namespace
Good luck
I'm having some trouble updating changes I made to a datatable via a dataadapter. I am getting "Concurrency violation: the UpdateCommand affected 0 of 10 rows"
'Get data
Dim Docs_DistributedTable As New DataTable("Docs_Distributed")
Dim sql = "SELECT DISTINCT CompanyID, SortKey, OutputFileID, SequenceNo, DeliveredDate, IsDeliveryCodeCounted, USPS_Scanned FROM Docs_Distributed_Test"
Using sqlCmd As New SqlCommand(sql, conn)
sqlCmd.CommandType = CommandType.Text
Docs_DistributedTable.Load(sqlCmd.ExecuteReader)
End Using
'Make various updates to some records in DataTable.
'Update the Database
Dim sql As String = "UPDATE Docs_Distributed "
sql += "SET DeliveredDate = #DeliveredDate "
sql += "WHERE SequenceNo = #SequenceNo"
Using transaction As SqlTransaction = conn.BeginTransaction("ProcessConfirm")
Try
Using da As New SqlDataAdapter
da.UpdateCommand = conn.CreateCommand()
da.UpdateCommand.Transaction = transaction
da.UpdateCommand.CommandText = sql
da.UpdateCommand.Parameters.Add("#DeliveredDate", SqlDbType.DateTime).SourceColumn = "DeliveredDate"
da.UpdateCommand.Parameters.Add("#SequenceNo", SqlDbType.Int).SourceColumn = "SequenceNo"
da.ContinueUpdateOnError = False
da.Update(Docs_DistributedTable)
End Using
transaction.Commit()
Catch ex As Exception
transaction.Rollback()
End Try
End Using
Now here's the catch. I am selecting DISTINCT records and essentially getting one row per SequenceNo. There may be many rows with the same SequenceNo, and I am hoping this will update them all. I'm not sure if this is related to my problem or not.
Your select is from "Docs_Distributed_Test" and your update is to "Docs_Distributed" - this may be the cause of your issue. Are the sequence ID's the same? (If not then perhaps it is indeed affecting 0 rows with it's update).
Other than that, you can always disable optimistic concurrency on your table-adapter and it will no longer enforce the validation (Though in this case that would likely result in no error but not updating any rows).
I don't understand the Microsoft-specific aspects of this, plus VB is often hard to follow. But this sequence seems suspect:
Using transaction As SqlTransaction = conn.BeginTransaction("ProcessConfirm")
Try
Using da As New SqlDataAdapter
da.UpdateCommand = conn.CreateCommand()
da.UpdateCommand.Transaction = transaction
conn.BeginTransaction is followed by conn.CreateCommand(). Isn't that a) useless, b) hazardous to the connection state, or c) potentially a race condition?