Getting data from SQL Server to Excel VBA Listview - sql-server

im trying to get the data in my database and show it in my listview (userform). I ran into an error saying the "Type Mismatch" im quite confuse on what part is the mismatch, already search what this error means but i've declare all my variables in correct data types. But since I have blanks or with null value it displays a error. On this line If not IsNull(Records(j, i)) Then li.ListSubItems.Add , , Records(j, i) Im trying to display null or empty on listview the mismatch error was gone but if column1 is blank and column2 have is not blank, the values on column2 will be pasted on column1.
Private Sub ListView_Data()
On Error GoTo ERR_Handler
Dim sql As String
Dim con As ADODB.Connection
Dim rst As New ADODB.Recordset
Dim Records As Variant
Dim i As Long, j As Long
Dim RecCount As Long
Set con = New ADODB.Connection
con.Open "Provider=SQLOLEDB;Data Source=10.206.88.119\BIWFO;" & _
"Initial Catalog=TESTDB;" & _
"Uid=user; Pwd=pass;"
sql = "select * from [TESTDB].[dbo].[tbl_MN_Omega_Raw]"
rst.Open sql, con, adOpenKeyset, adLockOptimistic
'~~> Get the records in an array
Records = rst.GetRows
'~~> Get the records count
RecCount = rst.RecordCount
'~~> Populate the headers
For i = 0 To rst.Fields.count - 1
ListView1.ColumnHeaders.Add , , rst.Fields(i).Name, 200
Next i
rst.Close
con.Close
With ListView1
.View = lvwReport
.CheckBoxes = False
.FullRowSelect = True
.Gridlines = True
.LabelWrap = True
.LabelEdit = lvwManual
Dim li As ListItem
'~~> Populate the records
For i = 0 To RecCount - 1
Set li = .ListItems.Add(, , Records(0, i))
For j = 1 To UBound(Records)
If not IsNull(Records(j, i)) Then li.ListSubItems.Add , , Records(j, i)
'End If
Next j
Next i
End With
ERR_Handler:
Select Case Err.Number
Case 0
Case Else
MsgBox Err.Description, vbExclamation + vbOKOnly, Err.Number
End Select
End Sub

Your type mismatch has nothing to do with null-values. It comes from a statement that looks rather unsuspicious: rst.RecordCount returns a Vartype LongLong, and assigning it to a Long throws a type mismatch.
You have 3 ways to fix this problem:
(1) Declare RecCount as Variant
(2) Convert rst.RecordCount into a Long: RecCount = CLng(rst.RecordCount)
(3) Don't use RecCount at all and instead use UBound(records, 2) (I prefer this method).
To find such errors, disable your error handler (comment the On Error Goto ERR_Handler). This will show the line that throws the error.
There is, however, a small issue when you have fields that contain null: You don't execute a li.ListSubItems.Add for those values, and therefore all values for the remaining fields of that row will be "shifted" to the left. You will need to run ListSubItems.Add also for null-Values, eg with
Dim fValue As Variant
fValue = Records(j, i)
If IsNull(fValue) Then fValue = "" ' or maybe "(null)"
li.ListSubItems.Add , , fValue

Related

Excel VBA - Populating userform listbox from sql server

Im trying to display the data from SQL Server to my userform listbox but it should have only show distinct value (not duplicating) currently salvaging the code i used in listview but i cant get it right, can someone help me please sorry im still learning. Thanks in advance. Here's my code below.
Private Sub LOB_List()
On Error GoTo ERR_Handler
Dim sql As String
Dim con As ADODB.Connection
Dim rst As New ADODB.Recordset
Dim Records As Variant
Dim i As Long, j As Long
Dim RecCount As Long
Set con = New ADODB.Connection
con.Open "Provider=SQLOLEDB;Data Source=10.206.88.119\BIWFO;" & _
"Initial Catalog=TESTDB;" & _
"Uid=user; Pwd=password1;"
sql = "select distinct lob from data_test"
rst.Open sql, con, adOpenKeyset, adLockOptimistic
Records = rst.GetRows
RecCount = rst.RecordCount
For i = 0 To rst.Fields.count - 1
Next i
rst.Close
con.Close
With ListBox1
Dim li As ListBox
For i = 0 To RecCount - 1
Set li = .ListBox.List(, , Records(0, i))
For j = 1 To UBound(Records)
If Not IsNull(Records(j, i)) Then li.ListSubItems.Add , , Records(j, i)
Next j
Next i
End With
ERR_Handler:
Select Case Err.Number
Case 0
Case Else
MsgBox Err.Description, vbExclamation + vbOKOnly, Err.Number
End Select
End Sub

Encountering Null value while loading record set into the array in Word VBA, throws Invalid use of Null (using ADODB connection with EXCEL)

Most important thing is that the code is written in Word VBA Editor and it's lunched from Word .docm file.
From this Word .docm file I'm connecting into the Excel file (using ADODB connection), which serves as a client database, and I'm reading whole sheet from that file (sheet name = "data") into a dynamic array which will be searched later.
Option Explicit
Private Sub UseADOSelect()
Dim connection As New ADODB.connection
Dim recSet As New ADODB.Recordset 'All the results of the query are placed in a record set;
Dim exclApp As Excel.Application
Dim exclWorkbk As Excel.Workbook
Dim mySheet As Excel.Worksheet
Dim wordDoc As Word.Document
Dim cntCntrl As ContentControl
Dim strPESELfromWord As String
Dim strQuery As String
Dim intWiersz As Integer
Dim intRemainder As Integer
Dim intRow As Integer
Dim arraySize As Long 'previously was integer = -32,768 to 32,767
Dim strSexDigit As String
Dim strArray() As String 'Dim strArray() As Long 'Dim strArray() As String
Dim i As Long
Set wordDoc = Word.ActiveDocument
Debug.Print wordDoc
'Set mySheet = exclApp.ActiveWorkbook.Sheets("sample")
'Debug.Print mySheet.Name
strPESELfromWord = Trim(Selection.Text)
Debug.Print strPESELfromWord
Word.Application.Visible = True
strSexDigit = Mid(strPESELfromWord, 10, 1) 'Extract 10th digit from PESEL number
Debug.Print strSexDigit
intRemainder = strSexDigit Mod 2
Debug.Print intRemainder
connection.Open "Provider = Microsoft.ACE.OLEDB.12.0;Data Source = X:\Roesler\Excel\FW 1\custdb.xlsm;" & _
"Extended Properties=""Excel 12.0 Macro;HDR=YES;IMEX=1;"";" 'now it works
'strQuery = "SELECT * From [Simple$]" '[Simple$] is the table name; in this case it's the sheet name;
strQuery = "SELECT * From [data$]" '[data$] is the table name; in this case it's the sheet name;
When the record set is read from the Excel file I need to write it into VBA array.
The problem I'm encountering is that: when I'm looping through the values in the record set, while loading this record set into the array in Word VBA Editor, Run-time error 94 - Invalid use of Null pops up when the first Null value is drawn from the record set into the array.
'recSet.Open strQuery, connection
recSet.Open strQuery, connection, adOpenStatic ' Or specify adOpenStatic in the Open method directly.
Debug.Print " RecordCount = " & recSet.RecordCount 'https://www.geeksengine.com/article/recordcount-ado-recordset-vba.html
Debug.Print recSet.EOF 'Returns a value that indicates whether the current record position is after the last record in a Recordset object.
'At the moment the value is "False".
Debug.Print recSet.BOF 'The BOF property returns a Boolean value that indicates if the current position in a Recordset object is just before the first record.
'If True, you are at BOF. If False, you are at or beyond the first record, but still inside the Recordset.
If recSet.BOF = True Then
recSet.MoveFirst
End If
'recSet.Open strQuery, connection
'recSet.CursorType = adOpenStatic
Debug.Print " RecordCount = " & recSet.RecordCount 'https://www.geeksengine.com/article/recordcount-ado-recordset-vba.html
arraySize = recSet.RecordCount 'I wanted to assign total number of records to arraySize variable to use it later in ReDim statement.
Debug.Print arraySize
ReDim strArray(1 To arraySize)
For i = 1 To arraySize
strArray(i) = recSet(i) 'Here the code crashes when the first Null value is encountered, during loading data into the array.
Next i
intRow = 2
' For Each cntCntrl In ActiveDocument.ContentControls
' If cntCntrl.Title = "02KlientPelneImie" Then cntCntrl.Range.Text = objExcel.Sheets("data").Cells(intWiersz, 4)
' If cntCntrl.Title = "02KlientNrDowodu" Then cntCntrl.Range.Text = objExcel.Sheets("data").Cells(intWiersz, 9)
' Next
What am I suppose to do with this.
There are empty cells in the Excel sheet I'm connecting to via ADODB connection with EXCEL. Nothing I can do about it.
How can I load a worksheet into a record set and later this record set into an array in Word VBA, while I have Null values inside??

Find and Replace Value in Table From DLookup Multiple Criteria VBA

I'm start to do programming in Access, and I really need help!!
My objective is to create a module that is run in "tbCustoProjeto" table and rewrite the field "Valor HH" values based on Dlookup. I found some solution (by azurous) who I think will solve this, but when I run the code, is returned
"object-required-error".
Sub redefineHH()
Dim objRecordset As ADODB.Recordset
Set objRecordset = New ADODB.Recordset
Dim i As Integer
Dim value As Variant
Dim HHTotal As Double
Set HHTotal = DLookup("[CustoTotalNivel]", "tbNivelNome2", "nUsuario='" & tbCustoProjeto!NumUsuario & "'" & "AND Numeric<=" & tbCustoProjeto!DataNumero)
'initated recordset obejct
objRecordset.ActiveConnection = CurrentProject.Connection
Call objRecordset.Open("tbCustoProjeto", , , adLockBatchOptimistic)
'find the target record
While objRecordset.EOF = False
'If objRecordset.Fields.Item(13).value > 0 Then
objRecordset.Fields.Item(13).value = HHTotal
objRecordset.UpdateBatch
'exit loop
'objRecordset.MoveLast
objRecordset.MoveNext
'End If
Wend
MsgBox ("Pesquisa Finalizada")
End Sub
Print of tbCustoProjeto
Print of tbNivelNome2
Please, someone can tell me where is the error? I don't know what to do.
Cannot reference a table directly like that for dynamic parameter. DLookup should pull dynamic criteria from recordset and within loop. Don't use apostrophe delimiters for number type field parameter.
Remove unnecessary concatenation.
Sub redefineHH()
Dim objRecordset As ADODB.Recordset
Set objRecordset = New ADODB.Recordset
objRecordset.Open "tbCustoProjeto", CurrentProject.Connection, , adLockBatchOptimistic
While objRecordset.EOF = False
objRecordset.Fields.Item(13) = DLookup("[CustoTotalNivel]", "tbNivelNome2", _
"nUsuario=" & objRecordset!NumUsuario & " AND Numeric <=" & objRecordset!DataNumero)
objRecordset.UpdateBatch
objRecordset.MoveNext
Wend
MsgBox ("Pesquisa Finalizada")
End Sub

Import EXCEL data to SQL Server without data conversion

I am trying to insert excel data into sql server tables. Each column should be imported with the exact same format that the user wrote in the source Excel.
I am using following query to fetch data
SELECT * FROM OPENROWSET( 'Microsoft.ACE.OLEDB.12.0', 'Excel 12.0 Xml;HDR=YES;IMEX=1;Database=H:\Loadloandata\Test\K3.xlsx',
'SELECT * FROM [Sheet1$]')
But now in the date column of excel we are receiving some float values( format issues from the users) as shown below
Because of the invalid data, the OLE provider convert the all other dates to float values in corresponding SQL table colums (float values corresponding to each date).If a date column is automatically cast to float I won't be able to know the original format of the data in the excel file, so all columns should be imported as varchar.
How can i prevent this datatype conversion? Based on google search i have used IMEX=1 in connection string to retrieve data for mixed data columns.
But it is not working !!
I think that you should get the data types from the SQL server table first to create the recordset, rather than letting Excel decide the datatypes from the Sheet. I believe Excel decides the data types by the first row, so in your case, it assumed Funded data was an integer, then casts any following strings into that data type.
Here is a full function that I use
This code is modified by me from the original source, which is mentioned in the comment. I made changes to deal with errors better.
Function ExportRangeToSQL(ByVal sourcerange As Range, _
ByVal conString As String, ByVal table As String, _
Optional ByVal beforeSQL = "", Optional ByVal afterSQL As String) As String
'https://www.excel-sql-server.com/excel-sql-server-import-export-using-vba.htm
' Object type and CreateObject function are used instead of ADODB.Connection,
' ADODB.Command for late binding without reference to
' Microsoft ActiveX Data Objects 2.x Library
' ADO API Reference
' https://msdn.microsoft.com/en-us/library/ms678086(v=VS.85).aspx
' Dim con As ADODB.Connection
On Error GoTo Finalise ' throw friendly user connection error
Dim con As Object
Set con = CreateObject("ADODB.Connection")
con.ConnectionString = conString
con.Open
Dim cmd As Object
Set cmd = CreateObject("ADODB.Command")
' BeginTrans, CommitTrans, and RollbackTrans Methods (ADO)
' http://msdn.microsoft.com/en-us/library/ms680895(v=vs.85).aspx
Dim level As Long
level = con.BeginTrans
cmd.CommandType = 1 ' adCmdText
If beforeSQL > "" Then
cmd.CommandText = beforeSQL
cmd.ActiveConnection = con
cmd.Execute
End If
' Dim rst As ADODB.Recordset
Dim rst As Object
Set rst = CreateObject("ADODB.Recordset")
With rst
Set .ActiveConnection = con
.Source = "SELECT * FROM " & table
.CursorLocation = 3 ' adUseClient
.LockType = 4 ' adLockBatchOptimistic
.CursorType = 0 ' adOpenForwardOnly
.Open
' Column mappings
Dim tableFields(100) As Integer
Dim rangeFields(100) As Integer
Dim exportFieldsCount As Integer
exportFieldsCount = 0
Dim col As Integer
Dim index As Variant
For col = 0 To .Fields.Count - 1
index = 0
index = Application.Match(.Fields(col).Name, sourcerange.Rows(1), 0)
If Not IsError(index) Then
If index > 0 Then
exportFieldsCount = exportFieldsCount + 1
tableFields(exportFieldsCount) = col
rangeFields(exportFieldsCount) = index
End If
End If
Next
If exportFieldsCount = 0 Then
Err.Raise 513, , "Column mapping mismatch between source and destination tables"
End If
' Fast read of Excel range values to an array
' for further fast work with the array
Dim arr As Variant
arr = sourcerange.Value
' The range data transfer to the Recordset
Dim row As Long
Dim rowCount As Long
rowCount = UBound(arr, 1)
Dim val As Variant
For row = 2 To rowCount
.AddNew
For col = 1 To exportFieldsCount
val = arr(row, rangeFields(col))
If IsEmpty(val) Then
Else
.Fields(tableFields(col)) = val
End If
Next
Next
.UpdateBatch
End With
rst.Close
Set rst = Nothing
If afterSQL > "" Then
cmd.CommandText = afterSQL
cmd.ActiveConnection = con
cmd.Execute
End If
Finalise:
If con.State <> 0 Then
con.CommitTrans
con.Close
End If
Set cmd = Nothing
Set con = Nothing
' Raise appropriate custom errors
Select Case Err.Number
Case -2147217843
Err.Raise 513, , "Issue connecting to SQL server database - please check login credentials"
Case -2147467259
If InStr(1, Err.Description, "Server does not exist") <> 0 Then
Err.Raise 513, , "Could not connect to SQL server, please check you are connected to the local network (in the office or on VPN)"
Else
Err.Raise 513, , "Issue connecting to SQL server database" & vbNewLine & Err.Description
End If
Case -2147217900
If InStr(1, Err.Description, "'PK_XL_Eng_Projects_QuoteRef'") <> 0 Then
Err.Raise 513, , "Quote already uploaded for this QuoteRef and Upload Time, please wait a minute before trying again" & vbNewLine & vbNewLine & Err.Description
Else
Err.Raise Err.Number, , Err.Description
End If
Case 0
' do nothing no error
Case Else
' re raise standard error
Err.Raise Err.Number, , Err.Description
End Select
End Function
Is there a reason why you using SSIS? I think that is best suited for the job.
Anyways, back to your issue. IMEX=1 is not enough. What you need is to check the registry entries
You need set TypeGuessRows and ImportMixedTypes within this registry path (this is for 32-bit office!):
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Office\12.0\Access Connectivity Engine\Engines\Excel
TypeGuessRows = 0 (the default is 8)
ImportMixedTypes = Text
What does TypeGuessRows do?
It tries to guess data type based on the number of rows defined. The default values is 8. That means it will check 8 rows to see what data type should be used. If you want to the engine to scan all the rows put 0 there. There is a catch, however, if your spreadsheet large, you could pay heavy performance penalty for such setting.
What does ImportMixedTypes do?
This is where your IMEX setting comes into the game. There are 3 possible values for IMEX setting 0, 1, 2:
0 is Export mode
1 is Import mode
2 is Linked mode (full update capabilities)
Only when setting IMEX=1 the registry value is honored. - with the default setting being ImportMixedTypes=Text. In any other value (0, 2) the value in registry is checked, if it is valid, but it does not influence the outcome. (you will get an error if invalid)
There are two valid values for ImportMixedTypes:
ImportMixedTypes=Text
ImportMixedTypes=Majority Type
The Majority Type is rarely used. What it does it counts type of each column and the majority type is then used for the whole column. The Text type will limit the row size to 255 characters, if you want to use more characters then Majority Type must be used and the majority must use more than 256 characters.

How to convert a Microsoft SQL date to a vba string?

I have a database in Microsoft SQL with 3 columns. The last column is a date which has the format: dd-mm-yyyy hh:mm-ss (ex: 20-May-15 22:31:38).
I managed to export the other 2 columns in Excel, but when I try to import the last column it gives me the next error: "Run-time error '3265': Application-defined or object-defined error".
My vba script is:
Private Sub CommandButton1_Click()
Dim con As ADODB.Connection
Dim rs As ADODB.Recordset
Dim r As Integer
Set con = New ADODB.Connection
Dim s As String
con.ConnectionString = "Provider=SQLOLEDB;Data Source=AEG-PC\WINCC; Initial Catalog=DBRapPlopeni; User ID=AEGRap; Password=1qaz2wsx; Trusted_Connection=yes"
con.Open
Set rs = New ADODB.Recordset
rs.ActiveConnection = con
rs.Open "EXEC SotoredProcedure 20,05,2015"
r = 5
Do While Not rs.EOF
Cells(r, 2) = rs.Fields(0)
Cells(r, 3) = rs.Fields(1)
Cells(r, 4) = rs.Fields(2) ' this field of date which cannot be imported
rs.MoveNext
r = r + 1
Loop
End Sub
I tried to convert date field in a string format but it didn't work for me.
Does anyone know how to solve this problem?
Many thanks in advance!
Had a similar issue and I used the GetRows method to store the data in an array and manipulate them from there.
Something like the below:
Replace:
Do While Not rs.EOF
Cells(r, 2) = rs.Fields(0)
Cells(r, 3) = rs.Fields(1)
Cells(r, 4) = rs.Fields(2) ' this field of date which cannot be imported
rs.MoveNext
r = r + 1
Loop
with
dim ar() as variant
ar = rs.GetRows
and then do a for loop to store the array data in the required cells.
for r =0 to ubound(ar,2) 'your array has 0 to ubound(ar,2) rows
cells(r,2) = ar(1,r)
cells(r,3) = ar(2,r)
cells(r,4) = ar(3,r)
next r
Hope this helps.

Resources