I have some code to read records from a database. when i read , the recordset variable modifies the table value to its own format.
For Eg:
In Database
Time value is 12345 (Not date & time) but when record set reads it, it
comes as For Eg: 23-06-2012
10:15:23
I just found that the recordset itself stores values in its own format after doing.
Set rs = CmdSqlData.Execute()
So is there any way to define a recordset as String?
Here is the code.
Dim rs As ADODB.RecordSet
Set rs = CmdSqlData.Execute()
Do While (rs.EOF = FALSE And rs.BOF = FALSE)
p = rs.GetRows(1)
cell(1,1) = p(0,0)
Loop
Can anyone please let me know how to read the data as String (as it is in database) so that no change in format will occur.
Note: I can not convert Excel cell format due to other requirements but I want to read everthing as String From Table
If you write
CStr(p(0,0))
To a cell, Excel will convert to the appropriate type for the content, so if p(0,0) is a number, the cell will be numeric.
However, if you write
ActiveSheet.Cells(1, 1) = "'" & p(0, 0)
Cell A1 will contain '2 to view, but can be manipulated as a string. This is left over from the early days of Excel, where to enter a string you had to prefix it with a single quote.
A1
2
=A1=2 FALSE
=A1="2" TRUE
Related
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
In my database serial-numbers are stored as an Integer.
I want to represent these numbers in a Access-frontend combobox with a different formation:
"121212345" --> "12.12.12345"
When a number is chosen it should be stored as an Integer again.
I already tried to populate the combobox by myself with some VBA code:
use a query to select all numbers
iterate all numbers and convert each to the new formation
put each converted number in the combobobox
When a selection is made i use the afterUpdate-Event to convert it back to an integer value and store it in my table.
This approach works very well but populating the combobox takes very long (4 sec for 20.000 numbers).
Is there a faster way of doing it?
When i just use the plain integer-field as recordsource, the box is populated in no time.
Edit:
'populate Combobobox:
Set db = CurrentDb
strSQL = "SELECT intSerialNumber FROM tblXXXX"
Set rs = db.OpenRecordset(strSQL)
Do While Not rs.EOF
strCurrentSerNum = rs.Fields(0).Value
Dim strSerNum As String
'xxxxxxxxx to xx.xx.xxxxx when possible
If (Len(strCurrentSerNum)) = 9 Then
strSerNum = Left(strCurrentSerNum, 2) & "." &
Mid(strCurrentSerNum, 3, 2) & "." & Right(strCurrentSerNum, 5)
Else
strSerNum = strCurrentSerNum
End If
cboSerNum.AddItem (strSerNum)
rs.MoveNext
Loop
You should use the Input Mask property for this.
A valid input mask to achieve exactly what you want is the following:
##.##.#####;;
First time poster, I finally had a question that I couldn't find an answer to here.
I have an MS Access query that returns 1 result (which is a number) that I want to store as an integer variable (x) so I can use it later for a loop. The issue is that because I'm using it as a recordset and the variable is an integer, I'm receiving a "Type Mismatch" error.
Right now I'm just storing the result to a cell and setting the variable equal to the cell:
Ws.Range("A1") = Db.OpenRecordset("SELECT COUNT(Asset_Name) FROM Assets WHERE Active = True").GetRows(1)
x = Ws.Range("A1")
Ws.Range("A1").Delete
And then later I just have a loop that runs x times:
For i = 0 To x
Basically, I just want to have some code that looks like this:
x = Db.OpenRecordset("SELECT COUNT(Asset_Name) FROM Assets WHERE Active = True").GetRows(1)
Any help here would be huge. Thank you!
The following should give you the correct result:
Dim x As Integer
Dim db As DAO.Recordset
db.MoveFirst
If IsNumeric(db.OpenRecordset("SELECT COUNT(Asset_Name) FROM Assets WHERE Active = True").Fields(0).Value) Then
x = CInt(db.OpenRecordset("SELECT COUNT(Asset_Name) FROM Assets WHERE Active = True").Fields(0).Value)
Else
MsgBox "The query did not return a number." & Chr(10) & "Aborting..."
End If
Note, that you are using DAO and not ADO as your original tags on the post indicated. Still, they both behave rather similar and the cursor is normally on the first row (when the data is returned). So, MoveFirst should not be necessary. Still, Microsoft themselves keep using it in its own sample code all the time. The first column if for DAO and ADO alike .Fields(0).
I have the following code in my Excel VBA that copies data from a table in SQL into Excel. This data is being inserted horizontally starting on cell C2, but I want it to be inserted vertically on column C.
Sheets("Control").Range("C2").CopyFromRecorset rsPubs
Where rsPubs is my ADO connection.
Basically, I just want this data transposed. What's an efficient way of doing this?
This is how rsPubs is created (the connection works fine as I'm actually getting the data):
' Create a recordset object.
Dim rsPubs As ADODB.Recordset
Set rsPubs = New ADODB.Recordset
With rsPubs
' Assign the Connection object.
.ActiveConnection = cnPubs
' Extract the required records.
.Open "SELECT * FROM Analytics.dbo.XBodoffFinalAllocation"
' Copy the records into cell B3 on Sheet1.
Sheets("Control").Range("C2").CopyFromRecordset rsPubs
' Tidy up
.Close
End With
cnPubs.Close
Set rsPubs = Nothing
Set cnPubs = Nothing
I cannot test this currently, but you could:
Sheets("Control").Range("C2").CopyFromRecorset rsPubs 'copy your data
Sheets("Control").Range("C2").Copy 'copy the data into clipboard
Sheets("Control").Range("C2").PasteSpecial xlPasteValues, xlPasteSpecialOperationNone, True, True
Also you could use the Transpose Worksheetfunction - however, I don't quite see a way right now to do this directly, expect your input data is transposed already.
Here is a nice official example and further informations on this topic: How to transfer data from an ADO Recordset to Excel with automation
Especially the "using GetRows" section.
This should do:
Dim resultset As Variant
Dim result As Variant
resultset = rsPubs.GetRows
result = Application.WorksheetFunction.Transpose(resultset)
Sheets("Control").Range("C2").Resize(UBound(result, 1), UBound(result, 2)) = result
http://www.teachexcel.com/excel-help/excel-how-to.php?i=147811
Edit 2 in the accepted answer doesn't work for me, but the following does (see http://www.mrexcel.com/forum/excel-questions/513845-copyfromrecordset-transpose.html for my source):
Public Sub PlaceTransposedResults(oResults As ADODB.Recordset, rTarget As Range)
Dim vTransposed As Variant
If Not oResults.EOF Then
vTransposed = oResults.GetRows
rTarget.Resize(UBound(vTransposed, 1) + 1, UBound(vTransposed, 2) + 1) = vTransposed
End If
End Sub
(this assummes that you haven't changed the array base with the OPTION BASE and that your version of Excel has Range.Resize and that oResults is never nothing)
One tweak on this is to make this a function and return the correctly sized range - useful if you want to resize a named range to cover the result set.
Another likely tweak is that you may want to optionally allow the user to ask for the field names to be added as the in the first column. I have found nothing better than:
Dim ix As Integer
For ix = 0 To oResults.Fields.Count - 1
rTarget.Offset(ix, 0) = oResults.Fields(ix).Name
Next ix
(of course you then have to offset your main results by 1 column in this case).
Untested:
Sub CopyTransposed(rng As Range, rs As ADODB.Recordset)
Dim x As Long, y As Long
x = 0
Do While Not rs.EOF
For y = 0 To rs.Fields.Count - 1
rng.Offset(y, x).Value = rs.Fields(y).Value
Next y
x = x + 1
rs.MoveNext
Loop
End Sub
This is really simple. It uses Excel's built-in transpose. Can be transposed in a single statement. No looping is needed. Tested and validated.
Dim vRecs, vRecsX
vRecs = rsPubs.GetRows
vRecsX = Application.Transpose(vRecs)
Sheets("Control").Range("C2").Resize(rsPubs.RecordCount, rsPubs.Fields.Count) = vRecsX
This code is copied directly from a working example.
Note, since this is a worksheet function, expect it to work with arrays of size only up to the number of columns on a worksheet. I believe columns-per-sheet varies between different versions of Excel, so it's a safe bet to determine your transpose limit based on your version of Excel.
"In the modern versions of Excel this is column XFD, which is 16,384 columns. In older versions of Excel (2003 and prior) the last column was IV which is 256 columns."
https://officemastery.com/_how-many-rows-and-columns-in-excel/
My suggestion is not to use VBA, at all. Microsoft already provided you the facility to import data from a database.
Data -> Import External Data
It will, then, create a QueryTable inside the sheet where you can just right-click and refresh in a regular basis. Another bonus is that you don't get the nasty macro warning. The QueryTable can be a table, query or stored procedure.
Try it!
I'm relatively experienced with Object oriented programming, but this is my first time ever working in Office with VBA and I'm entirely stumped by the syntax. I've been doing some searching and messing with it for the past hour or so, but have been trouble actually getting a macro that runs successfully and does what I need.
I'm attempting to loop through every cell in an Access table and apply the Trim function to the contents of that cell and, as a bonus, I'd like to remove all extra spaces in the string (if any). I.e. " Trim this__string " would simply become "Trim this string" (I used the underscore there to represent individual, multiple spaces since StackOverflow didn't want to show my multiple spaces).
Any code example of doing something like this, or at least something to get me close and then I can tinker with it, would be greatly appreciated. Thanks!
You can remove leading and trailing spaces with the Trim() function in a query.
UPDATE YourTable
SET text_field = Trim(text_field);
If you will be doing this from within an Access session, you could use Replace() to replace a sequence of two spaces with a single space.
UPDATE YourTable
SET text_field = Replace(text_field, ' ', ' ');
However you may need to run that Replace() query more than once to get all the contiguous space characters down to only one.
You could also do a regular expression-based replacement with a user-defined function. I don't know if that's worth the effort, though. And a user-defined function is also only available from within an Access application session.
I overlooked the "every cell in a table" aspect. That makes this more challenging and I don't think you can solve it with a standard macro or query. You can however use VBA code to examine the TableDef, and iterate through its fields ... then call your Trim and/or Replace operations on any of those fields whose data type is text or memo.
Here's a rough code outline to identify which fields of a given table are text type.
Public Sub FindTextFields(ByVal WhichTable As String)
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim fld As DAO.Field
Set db = CurrentDb
Set tdf = db.TableDefs(WhichTable)
For Each fld In tdf.Fields
If fld.Type = dbText Or fld.Type = dbMemo Then
Debug.Print "Do something with " & fld.Name
End If
Next
Set fld = Nothing
Set tdf = Nothing
Set db = Nothing
End Sub
Option Compare Database
Private Sub Command3_Click()
Call findField(Text1.Value)
End Sub
Public Function findField(p_myFieldName)
Dim db As Database, _
tb As TableDef, _
fd As Field
'''''''''Clearing the contents of the table
DoCmd.RunSQL "delete * from Field_Match_Found"
Set db = CurrentDb
For Each tb In db.TableDefs
For Each fd In tb.Fields
If fd.Name = p_myFieldName Then
strsql = "INSERT INTO Field_Match_Found Values (""" & tb.Name & """, """ & fd.Name & """)"
DoCmd.RunSQL strsql
End If
Next fd
Next tb
Set fd = Nothing
Set tb = Nothing
Set db = Nothing
If DCount("Account_number", "Field_Match_Found") = 0 Then
MsgBox ("No match was found")
Else
MsgBox ("Check Table Field_Match_Found for your output")
''''''''''making textbox blank for next time
Text1.Value = ""
End Function