I am working on a visual basic project. I have a mdb database connected to my project. I want to add a SELECT query that finds the results which are in array that i give it on my program
I have tried to write a statement like that:
SELECT kodu, adi_soyadi, sectigi_ders_say
FROM ogrenciler
WHERE kodu IN ?
But it does not work. In my page codes I have an array and I want to find results from "ogrenciler" table where the "kodu" is in my array.
Well, you could send that array to a temp table in Access, but that would prevent more then one user using the software at the same time. (or you could add some user name to the temp table. However, if the array of choices is small, say about max 50, then you can create the sql string.
eg:
Dim MySQL As String = "SELECT * from tblHotels WHERE ID IN("
Dim IdList(5) As Integer
Dim i As Integer
For i = 1 To 5
IdList(i) = i
Next
Dim MyList As String = ""
For i = 1 To 5
If MyList <> "" Then MyList = MyList & ","
MyList = MyList & IdList(i)
Next
MySQL = MySQL & MyList & ")"
Using MyCon2 As New OleDbConnection(My.Settings.OLESQL)
Dim da As New OleDbDataAdapter(MySQL, MyCon2)
Dim rstDat As New DataTable()
da.Fill(rstDat)
For i = 0 To rstDat.Rows.Count - 1
Debug.Print(rstDat.Rows(i).Item("HotelName"))
Next ' etc etc. etc.
End Using
So you can use the SQL format of:
SELECT * FROM tblHotels where ID IN (1,2,3)
And thus build up the "list". The only downside to this approach is that the sql string is limited to 2000 characters. So, if your list is larger then say 50 or so items, then you have to adopt a different approach.
Related
I have a Query qryRuleSets which outputs a table with 19 fields (that I do not want to save into an access table before that is suggested). I would like to get the field names and store them into an array so I can use that array in a for loop later on.
To find the number of fields that in the query result (to use in for loop later on) I have implemented the following, where the number of fields is stored in the variable numberfields -
numberfields = CurrentDb.QueryDefs("qryrulesets").Fields.Count
To actually get the name of these fields and store them in an array I am running into 2 problems:
1. Getting the field names from the query result
2. Setting up a dynamic array so that if the query ends up returning a table with more or less than 19 fields, it will still work
For my first problem:
I have tried to follow the steps in the following link: Get Column name from a query table but I can't figure it out.
To get the field names from the qry result I have tried the following but I'm not overly knowledgeable in vba/access so finding it hard to understand, even after a whole lot of googling:
Dim qry As QueryDef
Dim fieldNames As QueryDef
Dim firstcol As String
Set fieldNames = CurrentDb.CreateQueryDef(qry.qryrulesets)
firstcol = fieldNames.field(0).Name
For my second problem:
To store values in an array I have tried the following (as a test) and it works but I have to define the size of the array. Is there a way where it can be dynamic, i.e based on the value of the number of fields (found above stored in numberfields) :
Dim vardata(30) As Variant
For i = 1 To numberfields
vardata(i) = "hello"
Next i
I tried making the '30' above to a variable value but it didn't like that.
Any and all help will be appreciated. Thanks!
You can do like this:
Public Function GetFieldNames(ByVal QueryName As String) As String()
Dim Query As DAO.QueryDef
Dim FieldNames() As String
Dim Index As Integer
Set Query = CurrentDb.QueryDefs(QueryName)
ReDim FieldNames(0 To Query.Fields.Count - 1)
For Index = LBound(FieldNames) To UBound(FieldNames)
FieldNames(Index) = Query.Fields(Index).Name
Next
GetFieldNames = FieldNames()
End Function
i have a table that captures the details of Products. I want to be able to generate an Auto ID that contains special characters
I have been able to write code that generates the auto ID and also add a new one. But the issue arises when it gets to the 10th and 11th record.
It seems to be seeing the 9th record as the MAX in the database.
this makes it to throw error that there will be duplicate.
For example, record 9 generates CAT009, record 10 generates CAT0010 but instead to generate record 11 as CAT0011, it seems to keep generating CAT0010 because of the MAX function i used in the SELECT statement.
Sub auto()
Try
Dim cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & Application.StartupPath & "\inventory1.accdb")
cn.Open()
Dim dr As OleDbDataReader
Dim cmddr As New OleDbCommand
cmddr.CommandText = "SELECT MAX(category_id) as max_id FROM tblcategory "
cmddr.Connection = cn
dr = cmddr.ExecuteReader
dr.Read()
If IsDBNull(dr("max_id")) Then
autonumber = "CAT00" & 1
Else
Dim str As String
str = dr.Item("max_id").ToString()
Dim P As Double
Dim N As Double
N = Len(str)
P = N - 5
autonumber = "CAT00" & Convert.ToInt32(str.Substring(5, P))+ 1
End If
cn.Close()
Catch Ex As Exception
MsgBox(Ex.Message)
Console.WriteLine(Ex.Message)
End Try
End Sub
The overall concept is a duplicate of other questions, the key concern being proper formatting of the number with correct zero padding. There are various ways to do this in VB.Net, but the Int32.ToString(String) accepts a format string that can handle zero-padding. It's also unnecessary to calculate the string length, since Substring() has an overload to get all remaining characters to the right.
If IsDBNull(dr("max_id")) Then
autonumber = "CAT001"
Else
Dim str As String
str = dr.Item("max_id").ToString()
autonumber = "CAT" & (Convert.ToInt32(str.Substring(3)) + 1).ToString("000");
End If
If the first two zeros should be static (i.e. always "CAT00"), then it is critical to still format the changing portion with proper padding. Otherwise the text strings will not sort properly and so the numeric order will be ineffective. In that case, you should use something like
If IsDBNull(dr("max_id")) Then
autonumber = "CAT00001" '* NOT CAT001
Else
Dim str As String
str = dr.Item("max_id").ToString()
autonumber = "CAT00" & (Convert.ToInt32(str.Substring(5)) + 1).ToString("000");
End If
Of course in either case, be aware that the number of integer digits limits the range of valid numbers. For example, 3 digits ("000") has a maximum of 999.
A better approach is to use pure integer AutoNumbers in the database: 132 -> "CAT132". Then just format the number for display purposes, and when necessary parse user input text to extract the integer portion: "CAT0089" -> 89. This approach highly simplifies the backend code and leaves the AutoNumber functionality to the database itself... no need to have custom code to generate the numbers.
I'm trying to run a list of SQL queries where a condition exists for "code" and the values sit in a range of cells on another sheet (from cells A2 to A385).
I have the code below, however, I get an invalid object name for SQLQueries!$A2:A385
So, I understand the syntax is not correct but I'm struggling to find the correct one regardless of reading numerous articles.
Sub RunSQLQueries()
'Select SQLQueries sheet
Sheets("SQLQueries").Activate
'Initializes variables
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim ConnectionString As String
Dim StrQuery As String
'Setup the connection string for accessing MS SQL database
ConnectionString = "Provider=SQLOLEDB; Data Source=HOSTNAME; Initial Catalog=DBNAME; UID=domain\user; Integrated Security=SSPI"
'Opens connection to the database
cnn.Open ConnectionString
'Timeout
cnn.CommandTimeout = 900
'Build SQK queries
StrQuery = "SELECT * FROM table WHERE code IN (SELECT * FROM [SQLQueries!$A2:A385])"
'Performs the queries
rst.Open StrQuery, cnn
'Select Results sheet
Sheets("Results").Activate
'Dumps all the results from the StrQuery into cell A2 of the active sheet
Range("A2").CopyFromRecordset rst
End Sub
The result I'm expecting is for a SQL query to be run using each condition from the range of values with the results being populated on the "Results" sheet from cells A2 down
The query string is literally sent to the database server, and since your sql attempts to refer to an excel list that the server cannot access it returns an error. The server is looking for a table named [SQLQueries!$A2:A385]
To stick with your current plan, you will need to pass the the IN () clause literally or by vba variable that is formatted as such:
IN ( 'item1', 'item2' ...)
Note:You can remove single quotes if the items are numeric
I advise rethinking the plan by either
1) if it is possible to adjust things in the database side: Can you create a new reference table to join to the actual table or create a view that only returns desired rows? Then you would need a job that tweaks the filtering view/ table before running the query. The idea being you would not need to adjust the query each time bc a constant sql string would return the rows you need
Or
2) if the source table has say 100k rows or less, and data is not too wide, just select all the rows into excel in a new sheet, then filter that sheet (add a new column in excel that returns true using vlookup against your reference sheet) or use vlookup on your reference sheet to pull the desired columns
Here's a suggestion:
StrQuery = "SELECT * FROM table WHERE code IN (" & _
InList(Sheets("SQLQueries").Range("A2:A385"),True) & ")"
Function to create a SQL "in" list given a range:
Function InList(rng As Range, quoted As Boolean)
Dim qt, a, r As Long, c As Long, rv As String, v, sep As String
a = rng.Value
qt = IIf(quoted, "'", "")
For r = 1 To UBound(a, 1)
For c = 1 To UBound(a, 2)
v = Trim(a(r, c))
If Len(v) > 0 Then
rv = rv & sep & qt & v & qt
sep = ","
End If
Next c
Next r
InList = rv
End Function
Notes:
Pass False as the second argument if you have numeric values
I wouldn't use this for very large lists
Be very certain you're not at risk from possible SQL injection issues: parameterized queries are always preferable but do not work with "in" lists
I have a RichTextBox which has only text. How can I get the data (data is tab delimited) into my sql server table ? (I am not forced to use RTB so any other options would do fine as long as the entire process will be quick)
Example of text in RTB:
John 1985 (tab) 01 (tab) 19 (tab) 1.80 (tab) 70
Tony 1988 (tab) 02 (tab) 27 (tab) 1.67 (tab) 55
Table in sql Server called "Users":
Name, Year, Month, Date, Height, Weight
I found this code Dim lines As String() = myRichTextbox.Text.Split(New Char() {"\n"c})
so i just need to get each part of every line into a specific column...
any ideas ? I can't seem to get the data from RTB into SQL SERVER table. And i can't find it online... i will loop this process every 10 minutes so i don't want to save the RTB text into a file and then read from that file to save the data in table...
Once you have parsed the data you can use dynamic SQL or a stored procedure to insert the data into the DB.
SQL server manager can build the INSERT syntax for your table e.g.:
INSERT INTO [OIS].[dbo].[Burn_Type]
([Burn_Type]
,[Record_Create_Date]
,[Last_Update_Date]
,[Burn_Fee])
VALUES
(<Burn_Type, varchar(40),>
,<Record_Create_Date, datetime,>
,<Last_Update_Date, datetime,>
,<Burn_Fee, float,>)
You would need to replace the VALUES with your data then execute the SQL, here is some general code:
Public Function UpdateBySQL(ByVal SQL As String, Optional ByVal UserConnectString As String = "") As Integer
Dim sConStr As String = UserConnectString
If sConStr.Length = 0 Then sConStr = g.OISConnectString
Dim cmd As New Data.SqlClient.SqlCommand ' text commands only
Dim iCnt As Integer
Try
' wouldn't work for transactions
Using con As New SqlConnection(sConStr)
con.Open()
cmd.CommandText = SQL
cmd.Connection = con
iCnt = cmd.ExecuteNonQuery()
con.Close()
End Using
Catch ex As Exception
MsgBox(ex.Message & vbCrLf & vbCrLf & SQL)
End Try
Return iCnt
End Function
For higher security and performance use stored procedures.
You can split on the new line character (chr(10)) to get the rows, and then on each row you can split on tab character (chr(9)) to get the "columns"
Dim rows As String() = source.Split(Chr(10))
Dim columns As String()
For Each line As String In rows
columns = line.Split(Chr(9))
Next
So I have a one list box with values like DeptA, DeptB, DeptC & DeptD. I have a method that causes these to automatically populate in this list box if they are applicable. So in other words, if they populate in this list box, I want the resulting logic to say they are "Yes" in a boolean field in the table.
So to accomplish this I am trying to use this example of iteration to cycle through the list box first of all, and it works great:
dim i as integer
dim myval as string
For i = o to me.lstResults.listcount - 1
myVal = lstResults.itemdata(i)
Next i
if i debug.print myval, i get the list of data items that i want from the list box. so now i am trying to evaluate that list so that I can have an UPDATE SQL statement to update the table as i need it to be done.
so, i know this is a mistake, but this is what i tried to do (giving it as an example so that you can see what i am trying to get to here)
dim sql as string
dim i as integer
dim myval as string
dim db as database
sql = "UPDATE tblMain SET "
for i = 0 to me.lstResults.listcount - 1
myval = lstResults.itemdata(i)
If MyVal = "DeptA" Then
sql = sql & "DeptA = Yes"
ElseIF myval = "DeptB" Then
sql = sql & "DeptB = Yes"
ElseIf MyVal = "DeptC" Then
sql = sql & "DeptC = Yes"
ElseIf MyVal = "DeptD" Then
sql = sql & "DeptD = Yes"
End If
Next i
debug.print (sql)
sql = sql & ";"
set db= currentdb
db.execute(sql)
msgbox "Good Luck!"
So you can see why this is going to cause problems because the listbox that these values (DeptA, DeptB, etc) automatically populate in are dynamic....there is rarely one value in the listbox, and the list of values changes per OrderID (what the form I am using this on populates information for in the first place; unique instance).
I am looking for something that will evaluate this list one at a time (i.e. iterate through the list of values, and look for "DeptA", and if it is found add yes to the SQL string, and if it not add no to the SQL string, then march on to the next iteration). Even though the listbox populates values dynamically, they are set values, meaning i know what could end up in it.
Thanks for any help,
Justin
I don't understand what you're trying to accomplish. However, I suspect your UPDATE statement needs a WHERE clause. ('WHERE OrderID = X', with X replaced by the OrderID of the row you're editing)
I suppose you could create a dictionary object with values initially set to False.
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
dict.Add "DeptA", False
dict.Add "DeptB", False
' .. etc. '
Then go through the items in your listbox, changing the dict value to True.
dict(myval) = True
Finally, build your UPDATE statement based on the dictionary values.
But that all seems like too much work to me. So now I'm wondering about your table structure. Is tblMain set up similar to this?:
OrderID DeptA DeptB DeptC DeptD
------- ----- ----- ----- -----
127 True False False True
If so, consider a related table for the Dept information.
OrderID Which_Department
------- ----------------
127 DeptA
127 DeptD
The rule of thumb governing this is "columns are expensive; rows are cheap".
Edit: Seems to me you have two sets of items: SetA is all possible items; SetB is a subset of SetA. You want to produce a True for each item in SetB and a False for each SetA item which is not in SetB. Is that correct when you substitute dict (the dictionary object) for SetA and lstResults for SetB?
What I was trying to suggest is load dict with all the possible "DeptX" keys and assign them as False. Then iterate your lstResults and change each of those (in dict) to True. Afterward, build your SQL statement from dict.
Dim varKeys As Variant
Dim i As Integer
Dim strFragment As String
varKeys = dict.keys()
For i = LBound(varKeys) To UBound(varKeys)
strFragment = strFragment & ", " & varKeys(i) & " = " & dict(varKeys(i))
Next i
strFragment = Mid(strFragment, 3)
sql = sql & strFragment & "WHERECLAUSE"