VB.net - Check SQL Field to see if Bit is Set - sql

There is a bit field in my SQL table that I need to update to 1 if it's set at 0. I have the code written to set the field for every entry, but I need to check to see if it's at 0 already first so I can log what is changed.
Here's what I have already:
Public Function Update_User_to_TR(ByVal strUserName As String) As String
Dim myUserName As String = strUserName.Trim
Dim myReturn As String
Try
Dim sql As New SQL
Dim strQuery As String
strQuery = "Update dbo.USERS set user_field_Department_TR = 1 where USER_NAME = '" & myUserName & "'"
myReturn = sql.SQLUpdateWT(strQuery)
Catch ex As Exception
myReturn = ex.ToString
MsgBox(myReturn)
End Try
Return myReturn
End Function

You should upgrade to a stored procedure or a function, in this case, but here is a sample query.
"Declare #WillUpdate bit;Set #WillUpdate = 0;" & _
"If Exists(Select user_name from dbo.Users where user_name ='" & myUserName & _
"' and user_field_department_tr = 0 " & _
" Begin " & _
" Update dbo.USERS set user_field_Department_TR = 1 where USER_NAME = '" & myUserName & "';" & _
" Insert Into MyLog(field1, field2) " & _
" Values('sampledata', 'field was updated from 0 to 1');" & _
" End"
But please read the other comments and learn about sql injection and how it's bad, then learn how to use parameterized queries such as with ADO.NET.

Related

SQL Query using VBA and ADO record set - Code takes far less time to execute when run the second time

I have a VBA Code that involves, among other things, looping of an SQL query written as a Function. When I run the code for the first time, it takes nearly 155 seconds(which is understandable given the complexity of the calculation), when I run it for the second time it takes about 19 seconds. I would like to know why? Also how can I make it run faster? The SQL server version is 2008.
FunctionX() below, is used subsequently in For and Do while Loops, so I understand that a new Connection is created every time it runs.
Option Explicit
Public
Public conn As Object 'connection
________________________________________
Sub CreateConnection ()
Set conn = CreateObject("ADODB.connection")
Dim connstring As String
connstring = "Driver={SQL Server};Server=172.20.1.172;Database=WindAccess_dat_MRK;Uid=MRK_user;Pwd=MRK010usr;"
conn.Open connstring
conn.CommandTimeout = 120
End Sub
____________________________________
FunctionX(ActiveConnection as Object, arg1,arg2,....)
Dim SQLqryfunc1 As String
Dim SQLqryfunc2 As String
Dim SQLqryfunc3 As String
Dim fValue As Variant
Set wb = ThisWorkbook
Dim recset As Object
Set recset = CreateObject("ADODB.Recordset")
Dim ItemString1 As String
Dim ItemString2 As String
Dim ItemString3 As String
Dim ItemString4 As String
Dim ItemString5 As String
Dim StartZeit As String
Dim EndZeit As String
Select Case ChooseZeit
Case 1
StartZeit = Format(InputDateErsterTag, "yyyy-mm-dd hh:mm:ss.000")
EndZeit = Format(InputDateLetzterTag, "yyyy-mm-dd 23:50:ss.000")
ItemString3 = " AND HAL150.WTUR_AVG.MaxPwrSetpoint >=" & MaxPwrSetpoint_AvgVal
ItemString4 = " AND HAL150.WTUR_MIN.MaxPwrSetpoint >=" & MaxPwrSetpoint_MinVal
ItemString5 = " AND HAL150.WTUR_AVG.W >=" & WAvg_Min
Case 2
StartZeit = Format(InputDateErsterTag, "yyyy-mm-dd hh:mm:ss.000")
EndZeit = Format(InputDateLetzterTag, "yyyy-mm-dd hh:mm:ss.000")
ItemString3 = ""
ItemString4 = ""
ItemString5 = ""
End Select
Select Case Item
Case 1 ' 1= m
ItemString1 = " count(case when WindSpeed_Avg"
ItemString2 = " then 1 end)"
Case 2 ' 2= p
ItemString1 = " sum(case when WindSpeed_Avg"
ItemString2 = " then Leistung_Avg end)"
End Select
SQLqryfunc1 = "SELECT" _
& ItemString1 _
& " >=" _
& myWindSpeedFrom _
& " and" _
& " WindSpeed_Avg" _
& " <" _
& myWindSpeedTo _
& ItemString2 _
& " as '13.48 bis 14'" _
SQLqryfunc2 = " from" _
& " (" _
& " SELECT Time_Stamp, LDName as MONr,HAL150.WTUR_AVG.W as Leistung_Avg," _
& " WdSpd as WindSpeed_Avg, HAL150.WTUR_AVG.MaxPwrSetpoint as MaxPwrSetpoint_Avg,HAL150.WTUR_MIN.MaxPwrSetpoint as MaxPwrSetpoint_Min" _
& " FROM WSKD.RegCtrPeriodBlock" _
& " INNER JOIN HAL150.WNAC_AVG " _
& " ON WSKD.RegCtrPeriodBlock.idPBlock = HAL150.WNAC_AVG.idPBlock" _
& " INNER JOIN HAL150.WTUR_AVG" _
& " ON WSKD.RegCtrPeriodBlock.idPBlock = HAL150.WTUR_AVG.idPBlock" _
& " INNER JOIN WSKD.Components" _
& " ON WSKD.RegCtrPeriodBlock.IdLD = WSKD.Components.IdLD" _
& " INNER JOIN HAL150.WTUR_MIN" _
& " ON WSKD.RegCtrPeriodBlock.idPBlock = HAL150.WTUR_MIN.idPBlock" _
& " WHERE Time_Stamp BETWEEN" _
& " '" & StartZeit & "'" _
& " AND" _
& " '" & EndZeit & "'" _
& " AND" _
& " LDName in" _
& " (" & "'" & MONr & "'" & ")" _
& ItemString3 _
& ItemString4 _
& ItemString5 _
& " )" _
& " tbl"
SQLqryfunc3 = SQLqryfunc1 & SQLqryfunc2
'Debug.Print SQLqryfunc3
recset.Open SQLqryfunc3, myActiveConnection
fValue = recset.Getrows
Functionx = fValue(0, 0)
'Debug.Print Functionx
End Function
The second time your queries are executed they are likely cached by SQL server.
Lowest hanging fruit to making your query faster would be to take a sample output from this function and run it through SQL Server Management Studio with execution plan enabled: https://learn.microsoft.com/en-us/sql/relational-databases/performance/display-an-actual-execution-plan?view=sql-server-ver15 . It'll give you some tips on what indexes could be added to certain columns to make your query faster. If you have create privileges on database you can create some indexes to speed things up a bit. You'll also be able to see which parts of your query are the most expensive.
Also, dynamic SQL is hard on SQL server precisely because it has to come up with a new optimized execution plan each time and isn't able to keep it for very long. The reason it slows down again is because the optimized execution plan it creates the first time is ejected from the cache. SQL concatenation like this & " WHERE Time_Stamp BETWEEN" _ & " '" & StartZeit & "'" _ also opens you up to SQL injection attacks if the input is from the user. So if you can use parameters in your query instead using ADODB much like in this example answer here: https://stackoverflow.com/a/10353908/4641232 it would make your code more secure.
Another idea to optimize your code might be to move the processing of conditionals onto SQL server. For example, this case here:
Select Case ChooseZeit
Case 1
StartZeit = Format(InputDateErsterTag, "yyyy-mm-dd hh:mm:ss.000")
EndZeit = Format(InputDateLetzterTag, "yyyy-mm-dd 23:50:ss.000")
ItemString3 = " AND HAL150.WTUR_AVG.MaxPwrSetpoint >=" & MaxPwrSetpoint_AvgVal
ItemString4 = " AND HAL150.WTUR_MIN.MaxPwrSetpoint >=" & MaxPwrSetpoint_MinVal
ItemString5 = " AND HAL150.WTUR_AVG.W >=" & WAvg_Min
Case 2
StartZeit = Format(InputDateErsterTag, "yyyy-mm-dd hh:mm:ss.000")
EndZeit = Format(InputDateLetzterTag, "yyyy-mm-dd hh:mm:ss.000")
ItemString3 = ""
ItemString4 = ""
ItemString5 = ""
End Select
Instead of having two possible WHERE clauses, have your VBA create a SQL script that includes both and have SQL server make the distinction. For example, the WHERE clause in your output might look like this:
...
WHERE
...
AND
(
(
2 = 1 -- ChooseZeit == 2 in VB so that's where the 2 comes from.
AND HAL150.WTUR_AVG.MaxPwrSetpoint >= 4 -- I just picked a random number here.
AND HAL150.WTUR_MIN.MaxPwrSetpoint >= 2 -- I just picked a random number here.
AND HAL150.WTUR_AVG.W >= 3 -- I just picked a random number here.
)
OR
(
2 = 2 -- ChooseZeit == 2 in VB so that's where the 2 comes from.
)
)
...
With your WHERE clause constructed this way you give SQL Server a constant query structure to build an optimized path. If you use parameters, you can also now more easily move the scripted query created by VB into a stored procedure that you can compile on SQL server to possibly give even more gains.

Error 424 object required after NULL SQL query

I am running some EXCEL VBA code to update the contents of an ACCESS database table along the lines suggested here:
IF ##Rowcount = 0 -- SQL Syntax Error in Access
. When I execute the SELECT query, EXCEL VBA gives this error message:
Run-time error 424: Object required
I extracted the SQL string from the VBA Watch window and ran it as a Query in ACCESS. The first time I did this, there were no records becasue the table was empty, so I ran the INSERT query in ACCESS and then tried running the VBA code but got the same error message.
The code is here:
Public db As DAO.Database
' Open database
Public Sub OpenMdtDatabase()
Set db = DBEngine(0).OpenDatabase("SL_MDT_data_v1.accdb")
End Sub
' Update DB table
Sub UpdateDb()
' Initialise
Dim rs As DAO.Recordset
Set xlSht = Sheets("plot_data")
' Open database
Call OpenMdtDatabase
' Get the data to store
sname = xlSht.Cells(6, "R").Value
xfill = xlSht.Cells(6, "S").Value
xedge = xlSht.Cells(6, "T").Value
xstyl = xlSht.Cells(6, "U").Value
xsize = xlSht.Cells(6, "V").Value
' SQL stuff
sqlTxtSelect = "SELECT SeriesName FROM SeriesProperties WHERE SeriesName ='" & sname & "';"
sqlTxtUpdate = "UPDATE SeriesProperties " & _
sqlTxtUpdate = "SET SeriesFill = " & xfill & ", " & _
sqlTxtUpdate = "SeriesEdge = " & xedge & ", " & _
sqlTxtUpdate = "SeriesStyle = " & xstyl & ", " & _
sqlTxtUpdate = "SeriesSize = " & xsize & " " & _
sqlTxtUpdate = "WHERE SeriesName = '" & sname & "';"
sqlTxtInsert = "INSERT INTO SeriesProperties('" & sname & "') " & _
sqlTxtInsert = "VALUES(" & xfill & ", " & xedge & ", " & xstyl & ", " & xsize & ");"
Set rs = db.OpenRecordset(sqlTxtSelect)
If rs.RecordCount = 0 Then
DoCmd.RunSQL (sqlTxtInsert)
Else
DoCmd.RunSQL (sqlTxtUpdate)
End If
End Sub
I am guessing that there is something wrong with the SQL SELECT string. I tried setting this directly using
SELECT SeriesName FROM SeriesProperties WHERE SeriesName ='14/10-2:F2F_SLMC'
but still get the same error message. I have also tried removing the colon ...
The problem lies with the statement
DoCmd.RunSQL (sqlTxtInsert)
If I change this to
db.Execute (sqlTxtInsert)
then everything is fine. Should have scrolled to the end of the answer at the original link ....

Why is an action query not working in access VBA?

I tested an UPDATE query in Access's query design, and it works, but when I try to use it in my module, I get the error:
Invalid SQL statement; expected... or 'UPDATE'.
My query:
strSql = "UPDATE " & rs.Fields("tableName") & _
" SET " & rs.Fields("foreignKeyName") & " = " & rsContacts.Fields("contactId") & _
" WHERE contactId = " & ContactID
rs: a table that has tableName, foriegnKeyName of the tables to update
rsContacts: a list of contactIds (currently standing on a particular one).
The actual string comes out like this:
UPDATE myTable SET ContactId = 5 WHERE contactId = 2
If the query works, and it is an action query, why am I getting this error?
This is my full code:
Public Sub updateChildTables(ByVal ContactID As Long, ByVal CompanyID As Long)
Dim strSql As String
Dim rs As Recordset
Dim rsPending As Recordset
strSql = "SELECT contactID FROM contacts _
WHERE companyId = " & CompanyID & " and contactId <> " & ContactID
Set rs = CurrentDb.OpenRecordset(strSql)
If Not (rs.BOF And rs.EOF) Then
rs.MoveFirst
strSql = "SELECT * FROM childTables"
Set rsChild = CurrentDb.OpenRecordset(strSql)
rsChild.MoveFirst
Do While Not rsChild.EOF
strSql = "UPDATE " & rsChild.Fields("tableName") & " SET " & rsChild.Fields("foreignKeyName") & " = " & rs.Fields("contactId") & " WHERE contactId = " & ContactID
DoCmd.RunSQL strSql
rs.moveNext
Loop
rsChild.Close
Set rsChild = Nothing
End If
Here is my idea for debugging and possibly even resolving this.
Create a query from within Access normally -- name it UpdateMyTable, for the sake of this example.
Then, rather than using the DoCmd, actually execute this specific query from your VBA.
Dim qry As QueryDef
strSql = "UPDATE " & rsChild.Fields("tableName") & " SET " & _
rsChild.Fields("foreignKeyName") & " = " & _
rs.Fields("contactId") & " WHERE contactId = " & ContactID
Set qry = CurrentDb.QueryDefs("UpdateMyTable")
qry.SQL = strSql
qry.Execute
The big advantage of this is that you can very easily debug this from within Access to both see the rendered SQL and manually run it / tweak it.

Copy MS Access table to different MS Access

Please help; I wanted to copy an MS Access table and its data into another table at different MS Access database. I came across hundreds of access databases which has to be reformatted, I decided to write VB.Net code and format one table so that it can be copy to other hundreds instant of formatting one by one.
Here is my trial code:
Dim cmdCreate as New OleDb.OleDbCommand("SELECT * INTO [Hierarchy] IN "c:\hierarchy.pdb" FROM [Hierarchy] WHERE 0=1", con1)
cmdCreate.ExecuteNonQuery
Note: con1 datasource is deference with table2 directory.
here is a function in Access you can put a loop around with appropriate args. The dbSource and dbTarget are the full path names.
Public Function ExportTableToDatabase (TableName As String, dbSource As String, dbTarget As String, Optional Append As Boolean = False) As Boolean
On Error GoTo Error_Trap
Dim SQL As String
Dim db As DAO.Database
Set db = CurrentDb()
If Append Then
'The sql will use APPEND TO TABLE syntax
SQL = "INSERT INTO " & TableName & " IN """ & dbTarget & """ " _
& "SELECT " & TableName & ".* FROM " & TableName & " IN """ & dbSource & """ "
Else
'The sql will use CREATE TABLE syntax
SQL = "SELECT " _
& TableName & ".* INTO " & TableName & " " _
& "IN """ & dbTarget & """ " _
& "FROM " & TableName & " " _
& "IN """ & dbSource & """ "
End If
db.Execute SQL, dbFailOnError + dbSeeChanges
ExportTableToDatabase = True
Cleanup:
set db = nothing
Exit Function
Error_Trap:
msgbox Err.Number, Err.Description
Resume Cleanup
Resume
End Function

how to make condition to update table?

i want to make condition to update my table if there's already same data (in the same column) inserted in the table.
im using
If String.ReferenceEquals(hotel, hotel) = False Then
insertDatabase()
Else
updateDatabase()
End If
this is the updateDatabase() code...
Dim sql2 As String = "update infoHotel set nameHotel = N" & FormatSqlParam(hotel) & _
", streetAddress = N" & FormatSqlParam(StreetAddress) & _
", locality = N" & FormatSqlParam(Locality) & _
", postalCode = N" & FormatSqlParam(PostalCode) & _
", country = N" & FormatSqlParam(Country) & _
", addressFull = N" & FormatSqlParam(address) & _
", tel = N" & FormatSqlParam(contact) & _
"where hotel = '" & hotel & "')"
this is the formatSqlParam() code:
Function FormatSqlParam(ByVal strParam As String) As String
Dim newParamFormat As String
If strParam = String.Empty Then
newParamFormat = "'" & "NA" & "'"
Else
newParamFormat = strParam.Trim()
newParamFormat = "'" & newParamFormat.Replace("'", "''") & "'"
End If
Return newParamFormat
End Function
the function manage to go into updateDatabase() but has some error saying
"Incorrect syntax near 'Oriental'."
Oriental is the data inserted in the table. is it suitable to use ReferenceEquals?
im using vb.net and sql database..tq
You should be using parameterized queries instead of concatenating strings like so:
Dim sql2 As String = "Update InfoHotel" _
& "Set nameHotel = #nameHotel" _
& ", knownAs1 = #knownAs1" _
& ", knownAs2 = #knownAs2" _
& ", knownAs3 = #knownAs3" _
& ", knownAs4 = #knownAs4" _
& " Where hotel = #hotel"
If you used parameterized queries, you wouldn't have to worry about trying do quote replacement and potentially introducing a SQL Injection vulnerability.
You have a single quote in your data, as in:
Oriental's
Show us the code for FormatSqlParam() -- the bug is probably in there.
Or else you left out the single quotes around the hotel name:
where hotel = '" & hotel & "')"
I hope that's not it, because it would mean you're using the name as a key, a very bad idea.