i need to save to database at specific time at 8pm i cant seem to save it..
Public Sub updateDatabase(ByVal data As String) // update database using this function
With txtIn //textbox
'Dim con As OleDbConnection = New OleDbConnection("D:\POLI\SEM 5\PROJECT\Monitoring PH and Temperature\Monitoring PH and Temperature\PHTempdb.mdb")
'Dim sql2 As String = String.Empty
Dim conn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\POLI\SEM 5\PROJECT\Monitoring PH and Temperature\Monitoring PH and Temperature\PHTempdb.mdb") //database
'Dim dateTime.Now As String = Date
Dim date1 As Date = DateTime.Now
Dim str As String = date1.ToString("yyyy/MM/dd")
Dim insert As String = "INSERT INTO report (PHVALUE_TEMPERATURE, DATE_TIME) VALUES ('" & data & "', '" & DateTime.Now & "');"
Dim cmd As New OleDbCommand(insert, conn)
conn.Open()
If (DateTime.Now.Hour = 20 & DateTime.Now.Minute = 00) Then //save at 8 pm daily
cmd.ExecuteNonQuery() // execute
End If
System.Threading.Thread.Sleep(5000)
'.Clear()
'cmd.ExecuteNonQuery()
conn.Close()
' End If
'.Clear()
End With
End Sub
Private Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles sp.DataReceived
Dim str As String = sp.ReadExisting()
Invoke(myDelegate, str)
updateDatabase(str)
End Sub
If you can save your database programmatically normally by simply running a procedure, then you can add a Timer Control to your form and then set it to run in the appropriate of milliseconds from now.
Given the scheduled datetime and the current datetime you can use DateDiff to calculate the number of seconds from "now", and multiply by 1000 to get milliseconds.
You can find detailed instructions on using the Timer Control here and here.
Notes
At the beginning of the procedure called by the timer event, set the Enabled property to False to stop the procedure from running again. (Setting the interval to 0 does not cause the timer to stop.)
Since the timer interval was set relative to current time, it can't be "re-used" but if you want to automatically schedule the procedure again for the following day, you can simply recalculate the number of milliseconds and reset timer at the end of execution of your procedure.
The maximum value for the Interval is 2,147,483,647 milliseconds so the farthest in the future you can set a schedule using this method is about 25 days.
Related
I have a whole lot of stored procedures in a SQL Server database that need to be executed in sequence.
I have them setup in a table that have multiple sequences each containing a max of 5 stored procedures - so basically 5x threads:
I would like loop through each sequence and kick off each sequence's stored procedures at the same time. Then when all the stored procedures have completed, the next sequence of stored procedures can be kicked off.
I will be using SQL commands in .NET to kick of each stored procedure, but I need a way for them to all start at the same time and have the process wait for all to finish before moving on to the next sequence.
The idea of this is so that I can save time on processing data. If each stored procedure runs 2 minutes, running 5 at a time will take 2 minutes instead of 10 minutes.
Now I was told TPL would be a good approach. This is my first time working with multi-threading / TPL.
Below is a class that contain the properties and a function to execute a SQL Server stored procedure:
Public Class clsSQLStoredProcedure
Private mConnection As SqlClient.SqlConnection
Private mCommand As SqlClient.SqlCommand
Private mSQLStoredProcedure As String
Private mName As String
Private mStatus As String = "Pending"
Private mFeedback As DataTable
Public Property Connection() As SqlClient.SqlConnection
Set(ByVal o As SqlClient.SqlConnection)
mConnection = o
End Set
Get
Return mConnection
End Get
End Property
Public Property SQLStoredProcedure() As String
Set(ByVal o As String)
mSQLStoredProcedure = o
End Set
Get
Return mSQLStoredProcedure
End Get
End Property
Public Property Name() As String
Set(ByVal o As String)
mName = o
End Set
Get
Return mName
End Get
End Property
Public ReadOnly Property Status() As String
Get
Return mStatus
End Get
End Property
Public ReadOnly Property Feedback() As DataTable
Get
Return mFeedback
End Get
End Property
Public Function ExecuteSQLStoredProcedure()
On Error GoTo Errorhandler
Debug.Print(mName & " Start # " & Now().ToString)
mStatus = "Running"
If mConnection.State <> ConnectionState.Open Then mConnection.Open()
mCommand = New SqlClient.SqlCommand(mSQLStoredProcedure, mConnection)
mCommand.CommandTimeout = 0
mCommand.ExecuteNonQueryAsync()
mStatus = "Completed"
Debug.Print(mName & " Completed # " & Now().ToString)
Exit Function
Errorhandler:
mStatus = "Failed"
Debug.Print(mName & " Failed # " & Now().ToString & " - " & Err.Description)
End Function
End Class
This is the code I use to perform tasks (TPL) to start 3 stored procedures at the same time:
Imports System.Threading
Imports System.Threading.Tasks
Module modThreading
Public Sub TestThreading()
Dim oSP1 As New clsSQLStoredProcedure
oSP1.SQLStoredProcedure = "EXEC CURRO_DW.conform.usp_ETLFactCollectorActivity -99"
oSP1.Connection = gGDM.Database.Connection
oSP1.Name = "usp_ETLFactCollectorActivity"
'oSP1.ExecuteSQLStoredProcedure()
Task.Run(action:=oSP1.ExecuteSQLStoredProcedure())
Dim oSP2 As New clsSQLStoredProcedure
oSP2.SQLStoredProcedure = "EXEC CURRO_DW.conform.usp_ETLDimPerson -99"
oSP2.Connection = gGDM.Database.Connection
oSP2.Name = "usp_ETLDimPerson"
'oSP2.ExecuteSQLStoredProcedure()
Task.Run(action:=oSP2.ExecuteSQLStoredProcedure())
Dim oSP3 As New clsSQLStoredProcedure
oSP3.SQLStoredProcedure = "SELECT 1"
oSP3.Connection = gGDM.Database.Connection
oSP3.Name = "TEST"
'oSP3.ExecuteSQLStoredProcedure()
Task.Run(action:=oSP3.ExecuteSQLStoredProcedure())
MsgBox("Done")
End Sub
End Module
However they still seem to run one after the other even though some are suppose to run instant while other take about 1min.
Don't keep your connection open for the life of your application. You should open and close a database connection as late and early as possible, respectively. A database connection runs on a single thread so the first task, although being run asynchronously, will block the second, et cetera.
So create a new connection for each stored procedure and perhaps WaitAll at the end. You can put the Tasks in a collection to do this.
Dim gGDM1 As New DatabaseContext()
Dim gGDM2 As New DatabaseContext()
Dim gGDM3 As New DatabaseContext()
Try
Dim oSP1 As New clsSQLStoredProcedure
oSP1.SQLStoredProcedure = "EXEC CURRO_DW.conform.usp_ETLFactCollectorActivity -99"
oSP1.Connection = gGDM1.Database.Connection
oSP1.Name = "usp_ETLFactCollectorActivity"
Dim oSP2 As New clsSQLStoredProcedure
oSP2.SQLStoredProcedure = "EXEC CURRO_DW.conform.usp_ETLDimPerson -99"
oSP2.Connection = gGDM2.Database.Connection
oSP2.Name = "usp_ETLDimPerson"
Dim oSP3 As New clsSQLStoredProcedure
oSP3.SQLStoredProcedure = "SELECT 1"
oSP3.Connection = gGDM3.Database.Connection
oSP3.Name = "TEST"
Dim tasks As New List(Of Task)()
tasks.Add(Task.Run(oSP1.ExecuteSQLStoredProcedure))
tasks.Add(Task.Run(oSP2.ExecuteSQLStoredProcedure))
tasks.Add(Task.Run(oSP3.ExecuteSQLStoredProcedure))
Task.WaitAll(tasks.ToArray())
Finally
gGDM1.Dispose()
gGDM2.Dispose()
gGDM3.Dispose()
MsgBox("Done")
End Try
You need to modify the Dim gGDM As New DatabaseContext() lines to create a new context, however you have done it globally, but instead for each call. They are immediately disposed of when you're done.
I'm updating SQL Server from VB.NET and keep getting the 'Query Timeout Error', I have lot's of sub routines that I run in sequence that look like the following:
Public Shared Sub Update_DailyRatings()
Dim stallStats As String = ""
Dim win As Integer = 0
Dim mSplit As Array
Dim cn As OleDbConnection = New OleDbConnection(MainForm.connectStringPublic)
cn.Open()
Dim selectString As String = "Select * FROM DailyRatings"
Dim cmd As OleDbCommand = New OleDbCommand(selectString, cn)
Dim reader As OleDbDataReader = cmd.ExecuteReader()
While (reader.Read())
stallStats = Get_Stall_Stats(reader("Track").ToString, CInt(reader("Stall")), CDbl(reader("Distance")))
If stallStats = "" Then
MainForm.NonQuery("UPDATE DailyRatings SET StallWin = 999 WHERE Horse = '" & reader("Horse").ToString & "'")
Else
mSplit = Split(stallStats, ",")
win = mSplit(0)
MainForm.NonQuery("UPDATE DailyRatings SET StallWin = " & win & " WHERE Horse = '" & reader("Horse").ToString & "'")
End If
End While
reader.Close()
cn.Close()
End Sub
The NonQuery sub looks like this:
Public Sub NonQuery(ByVal SQL As String)
Dim query As String = SQL
Try
Dim cn3 As OleDbConnection = New OleDbConnection(connectStringPublic)
cn3.Open()
Dim cmd As OleDbCommand = New OleDbCommand(query, cn3)
cmd.CommandTimeout = 90
cmd.ExecuteNonQuery()
cn3.Close()
cn3.Dispose()
cmd.Dispose()
OleDbConnection.ReleaseObjectPool()
Catch e As System.Exception
Clipboard.SetText(query)
MsgBox(e.Message)
Finally
End Try
End Sub
As you can see I've been trying ideas to fix this that I found in other threads such as extending the timeout and using the Dispose() and ReleaseObjectPool() methods but it hasn't worked, I still get query timeout error at least once when running all my subs in sequence, it's not always the same sub either.
I recently migrated from Access, this never used to happen with Access.
If you are dealing with Sql Server why are you using OleDb? I guessed that is was really access.
While your DataReader is open, your connection remains open. With the amount of processing you have going on, it is no wonder that your connection is timing out.
To begin, connections and several other database objects need to be not only closed but disposed. They may contain unmanaged resources which are released in the .Dispose method. If you are using an object that exposes a .Dispose method use Using...End Using blocks. This will take care of this problem even if there is an error.
Actually you have 2 distinct operations going on. First you are retrieving DailyRatings and then you are updating DailyRatings base on the data retrieved. So we fill a Datatable with the first chunk of data and pass it off to the second operation. Our first connection is closed and disposed.
In operation 2 we create our connection and command objects just as before except now our command has parameters. The pattern of the command is identical for every .Execute, only the values of the parameters change. This pattern allows the database, at least in Sql Sever, to cache a plan for the query and improve performance.
Public Shared Function GetDailyRatings() As DataTable
Dim dt As New DataTable
Using cn As New OleDbConnection(MainForm.connectStringPublic),
cmd As New OleDbCommand("Select * FROM DailyRatings", cn)
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
Return dt
End Function
Public Sub UpdateDailyRatings()
Dim dt = GetDailyRatings()
Using cn As New OleDbConnection(connectStringPublic),
cmd As New OleDbCommand("UPDATE DailyRatings SET StallWin = #Stall WHERE Horse = #Horse")
cmd.Parameters.Add("#Stall", OleDbType.Integer)
cmd.Parameters.Add("#Horse", OleDbType.VarChar)
cn.Open()
For Each row As DataRow In dt.Rows
cmd.Parameters("#Horse").Value = row("Horse").ToString
Dim stallStats As String = Get_Stall_Stats(row("Track").ToString, CInt(row("Stall")), CDbl(row("Distance")))
If stallStats = "" Then
cmd.Parameters("#Stall").Value = 999
Else
cmd.Parameters("#Stall").Value = CInt(stallStats.Split(","c)(0))
End If
cmd.ExecuteNonQuery()
Next
End Using
End Sub
Private Function GetStallStats(Track As String, Stall As Integer, Distance As Double) As String
Dim s As String
'Your code here
Return s
End Function
Note: OleDb does not pay attention to parameters names. It is the order that they appear in the query statement must match the order that they are added to the Parameters collection.
It's possible that OleDbDataReader is locking your table or connection as it get the data with busy connection. You can store the data in a DataTable by using OleDbDataAdapter and loop through it to run your updates. Below is the snippet how your code would look like:
Dim cmd As OleDbCommand = New OleDbCommand(selectString, cn)
Dim adapter As OleDbDataAdapter = New OleDbDataAdapter(cmd)
Dim dt As New DataTable()
adapter.Fill(dt)
For Each reader As DataRow In dt.Rows
stallStats = Get_Stall_Stats(reader("Track").ToString, CInt(reader("Stall")), CDbl(reader("Distance")))
If stallStats = "" Then
MainForm.NonQuery("UPDATE DailyRatings SET StallWin = 999 WHERE Horse = '" & reader("Horse").ToString & "'")
Else
mSplit = Split(stallStats, ",")
win = mSplit(0)
MainForm.NonQuery("UPDATE DailyRatings SET StallWin = " & win & " WHERE Horse = '" & reader("Horse").ToString & "'")
End If
Next
cn.Close()
I have a dialog with a combobox listing the years an event was held.
Changing the year, changes the following list boxes
One list box 'called inEvent' shows all golfers the attended said event.
The other list box called 'available' that shows every golfer we have in our database that did not attend that years event
It has two buttons. One removes golfers from 'inEvent' and moves them to 'available'. This button works.
The other button does the opposite. It adds available golfers to the selected event year. But it gives me the error -
"The statement has been terminated. Cannot insert the value NULL into column 'intGolferEventYearID', table 'dbo.TGolferEventYears'; column does not allow nulls. INSERT fails."
Changing any line of code in VB results in a different error. So I think the error has to come from SQL itself which I don't know much about. Only other thing I can think of is the listbox is giving the wrong information.
Private Sub btnAddAuto_Click(sender As Object, e As EventArgs) Handles btnAddAuto.Click
Dim strInsert As String = ""
Dim cmdInsert As OleDb.OleDbCommand ' used for our Select statement
Dim dt As DataTable = New DataTable ' table we will load from our reader
Dim intRowsAffected As Integer
' open the DB
OpenDatabaseConnectionSQLServer()
' Build the select statement
strInsert = "INSERT INTO TGolferEventYears ( intGolferID, intEventYearID) Values (" & lstAvailable.SelectedValue & ", " & cboEvents.SelectedIndex + 1 & ")"
' Retrieve all the records
cmdInsert = New OleDb.OleDbCommand(strInsert, m_conAdministrator)
intRowsAffected = cmdInsert.ExecuteNonQuery()
' close the database connection and reload the form so the changes are shown
CloseDatabaseConnection()
frmEventsGolfers_Load(sender, e)
End Sub
I separated the data access code from the user interface. This will make it easy to remove data access entirely from the Form if you later desire.
Private Sub MoveGolfer(GolfID As Integer, YearID As Integer)
'If you keep your connections local you can be sure they are
'closed and disposed which is what the Using...End Using blocks do.
Using cn As New SqlConnection("Your connection string")
Using cmd As New SqlCommand("INSERT INTO TGolferEventYears ( intGolferID, intEventYearID) Values (#Golf, #Year;")
'Always use parameters to protect against Sql injection
cmd.Parameters.Add("#Golf", SqlDbType.Int).Value = GolfID
cmd.Parameters.Add("#Year", SqlDbType.Int).Value = YearID
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Using
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim GolferID As Integer = CInt(lstAvailable.SelectedValue)
Dim Year As Integer = cboEvents.SelectedIndex + 1
Try
MoveGolfer(GolferID, Year)
Catch ex As Exception
'Catch a more specific exception and handle accordingly
MessageBox.Show(ex.Message)
End Try
End Sub
Since I don't really understand SQL I didn't realize my PK didn't have the IDENTITY tag added in the table. Adding this fixed my issue.
Here is the code I added
Dim strSelect As String
Dim cmdSelect As OleDb.OleDbCommand
Dim drSourceTable As OleDb.OleDbDataReader
Dim intNextHighestRecordID As
strSelect = "SELECT MAX(intDealerAutos) + 1 AS intNextHighestRecordID " &
" FROM TDealerAutos"
'Excute command
cmdSelect = New OleDb.OleDbCommand(strSelect, m_conAdministrator)
drSourceTable = cmdSelect.ExecuteReader
'Read result( highest ID )
drSourceTable.Read()
'Null? (Empty Table)
If drSourceTable.IsDBNull(0) = True Then
'Yes, start numbering at 1
intNextHighestRecordID = 1
Else
'No, get the next highest ID
intNextHighestRecordID = CInt(drSourceTable.Item(0))
End If
'Build the select statement
strInsert = "INSERT INTO TDealerAutos ( intDealerAutos, intDealerID, intAutoID)" &
"Values (" & intNextHighestRecordID & ", " & cboDealers.SelectedValue & ", " & lstAvailable.SelectedValue & ")"
I have this:
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
Dim con As New SqlConnection
Dim myCommand As New SqlCommand
Try
Dim a As String
con.ConnectionString = "Data Source=SVNAV;Initial Catalog=NAV_Vermorel_Live;User ID=sa;Password=1234"
con.Open()
Dim laser As String
Dim debit As String
Dim indoire As String
Dim uzinaj As String
Dim dlaser As Nullable(Of DateTime) = DateTime.Now
Dim ddebit As Nullable(Of DateTime) = DateTime.Now
Dim dindoire As Nullable(Of DateTime) = DateTime.Now
Dim duzinaj As Nullable(Of DateTime) = DateTime.Now
If NewCheckBox1.Checked = True Then
laser = "Finished"
Else
laser = "In Progress"
dlaser = Nothing
End If
If NewCheckBox2.Checked = True Then
debit = "Finished"
Else
debit = "In Progress"
ddebit = Nothing
End If
If NewCheckBox3.Checked = True Then
indoire = "Finished"
Else
indoire = "In Progress"
dindoire = Nothing
End If
If NewCheckBox4.Checked = True Then
uzinaj = "Finished"
Else
uzinaj = "In Progress"
duzinaj = Nothing
End If
a = "INSERT INTO [dbo].[SC Vermorel SRL$PregatirePROD]
(
[FPO]
,[Articol]
,[Descriere]
,[Cantitate]
,[LASER]
,[DEBITARE]
,[INDOIRE]
,[UZINAJ]
,[EndDateLASER]
,[EndDateDEBIT]
,[EndDateINDOIRE]
,[EndDateUZINAJ])
VALUES
(#FPO,
#Articol
,#Descriere
,#Cantitate
,#LASER
,#DEBITARE
,#INDOIRE
,#UZINAJ
,#EndDateLASER
,#EndDateDEBIT
,#EndDateINDOIRE
,#EndDateUZINAJ)"
myCommand = New SqlCommand(a, con)
myCommand.Parameters.AddWithValue("#FPO", txtFpo.Text)
myCommand.Parameters.AddWithValue("#Articol", txtItem.Text)
myCommand.Parameters.AddWithValue("#Descriere", txtDesc.Text)
myCommand.Parameters.AddWithValue("#Cantitate", txtQty.Text)
myCommand.Parameters.AddWithValue("#LASER", laser)
myCommand.Parameters.AddWithValue("#DEBITARE", debit)
myCommand.Parameters.AddWithValue("#INDOIRE", indoire)
myCommand.Parameters.AddWithValue("#UZINAJ", uzinaj)
myCommand.Parameters.AddWithValue("#EndDateLaser", dlaser)
myCommand.Parameters.AddWithValue("#EndDateDEBIT", ddebit)
myCommand.Parameters.AddWithValue("#EndDateINDOIRE", dindoire)
myCommand.Parameters.AddWithValue("#EndDateUZINAJ", duzinaj)
myCommand.ExecuteNonQuery()
Catch ex As Exception
MessageBox.Show("Eroare ..." & ex.Message, "Inserare campuri")
Finally
con.Close()
End Try
Me.SC_Vermorel_SRL_PregatirePRODTableAdapter.Fill(Me.NAV_Vermorel_LiveDataSet._SC_Vermorel_SRL_PregatirePROD)
End Sub
The table design from, prtscreen from SSM:
Im trying to add the DateTime.Now value of dlaser into an SQL field. I get SQL type overflow, dates must be between etc etc.
The format of date witch SMS displays is: 2016-09-30 14:58:46.343. SQL Server 2005.
How can i be sure that vb net application outputs datetime in same format?
In the Else part you leave VB variable dlaser uninitialized, which means it has value 0001-01-01 00:00:00. But that variable is always used for parameter #EndDateLaser to set column [EndDateLASER].
Column [EndDateLASER] has SQL type datetime, but datetime does not allow 0001-01-01, the minimum value allowed is 1753-01-01.
Apart from that, I wonder why you sometimes add a #dlaser SqlParameter (with value DBNull). For the query as shown that parameter is irrelevant because it does not use #dlaser anywhere. And also, why add it only in one situation, while your query is fixed.
Please Use This
DateTime.Now.ToString("dd-MMM-yyyy")
in Place of
DateTime.Now
and dlaser is take string
dim dlaser as string
Ok so I'm trying to writing VBA code to automate as much as possible. What I need it to do is read from a field in a table and if it meets the conditions than it copy that to a new table. It's for rotation purposes. If CurrentDate equals NextDateOut than whatever value of that item I want to go to a certain table but also want to update values in the current table. NextDateOut will be the new LastDateOut value in the table and NextDateIn will be 10 days from NextDateIn and NextDateOut will be 10 days from then. I can write the math logic of this it's just the comparing my values from my table to my constant which right now is CurrentDate and updating the values and writing the values to a certain table when the conditions meet.
Here's the code so far and there's a lot of mistakes trying to figure it out as well.
Option Explicit
Sub Run()
'Declarations for grabbing data from the database for the VBA
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim strSQL As String
'Open connection to current Access database
Set db = CurrentDb()
'Declarations for variables to deal with dates
Dim CurrentDate As Date
Dim NextDateOut As Date
Dim NextDateIn As Date
Dim LastDateOut As Date
Dim LastDateIn As Date
'Setting a consistant value, technically not a constant value since there's no "const"
CurrentDate = Date
'Will take this out eventually
MsgBox (CurrentDate)
strSQL = "SELECT Next Date Out FROM Tapes Where Next Date Out = CurrentDate"
Set rst = db.OpenRecordset(strSQL, dbOpenDynaset)
With rst
If .RecorCount > 0 Then
.MoveFirst
.Edit
!Next Date Out = (CurrentDate+20)
.Update
End If
End With
End Sub
Thanks in ADVANCE!!! I'm making progress but hitting walls on the way. THANKS AGAIN!!!
I think you can solve this directly with queries.
Let's split this problem into steps:
If NextDateOut (a field in your table) equals currentDate (a variable in your code), then:
You need to move all records for which the condition is true to a new table
For the records that remain in the table, you need to update LastDateOut to currentDate, nextDateIn to currentDate + 10 and nextDateOut to currentDate + 20
If this is correct, you can try this:
dim strSQL as String
dim currentDate as Date
...
' Step 1: Copy the records to a new table '
strSQL = "insert into otherTable " & _
"select * from tapes " & _
"where [nextDateOut]=" & CDbl(currentDate)
doCmd.runSQL strSQL
' Step 2: Delete the records just copied '
strSQL = "delete from tapes where [nextDateOut]=" & CDbl(currentDate)
doCmd.runSQL strSQL
' Step 3: Update the dates in ALL the records remaining the "tapes" table '
strSQL = "update tapes " & _
"set [lastDateOut]=" & CDbl(currentDate) & ", " & _
"set [nextDateIn]=" & CDbl(currentDate + 10) & ", " & _
"set [nextDateOut]=" & CDbl(currentDate + 20)
doCmd.runSQL strSQL
...
Note: I use CDbl(currentDate) to avoid problems with Date formats (MS Access stores dates as double values, with the integer part representing days and the decimal part representing fractions of days)
Hope this helps you