Insert Data into SQL Table from an Excel Sheet - sql-server

if I have the following table in SQL,
Item Desc Type Location Quantity Unit_Price
A AAA X 1 0 20.00
B BBB Y 2 0 10.00
B CCC X 2 0 50.00
C DDD Z 1 0 150.00
C EEE Y 3 0 70.00
D FFF Z 3 0 65.00
And the following Excel Sheet
Item Location Quantity
A 1 1
B 1 2
B 2 3
C 1 40
C 3 500
D 3 10
How do I insert these quantities in to the SQL table reading from my Excel table ?

To do this with T-SQL, you can follow this tutorial in detail and start by pulling the data into a temporary table, as shown in the following SELECT…INTO statement:
SELECT * INTO #ProductInfo
FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0',
'Excel 12.0 Xml; HDR=YES; IMEX=1;
Database=C:\DataFiles\ProductData.xlsx',
[vProduct$]);
Using the OPENROWSET in-build function to retrieve Excel data where the first argument is the name of the provider which can be one of two providers:
Microsoft.Jet.OLEDB.4.0: Use on SQL Server 32-bit editions for Excel
2003 files (or earlier).
Microsoft.ACE.OLEDB.12.0: Use on SQL Server
32-bit editions for Excel 2007 files (or later) or on SQL Server
64-bit editions for any Excel files.
The second OPENROWSET argument defines the provider string delimited by a semi-colon with the first part specifying the file type:
For Excel ’97-2003 (.xls) files, use Excel 8.0.
For Excel 2007-2010 (.xlsx) files, use Excel 12.0 Xml.
For Excel 2007-2010 macro-enabled (.xlsm) files, use Excel 12.0
Macro.
For Excel 2007-2010 non-XML binary (.xlsb) files, use Excel 12.0.
The second part of the argument specifies the file’s path and file name. The third argument is the name of the spreadsheet we want to access with the dollar sign ($) appended and enclosed in brackets, as in [Products$], for example.
Once you have the data into the temporary table #ProductInfo, you can then convert, filter the data as necessary using an inner join and then update the Quantity field:
UPDATE
p
SET
p.Quantity = temp.Quantity
FROM dbo.Product AS p
INNER JOIN #ProductInfo AS temp
ON temp.Item = p.Item
AND temp.Location = p.Location;

Right Click on Database -> Tasks -> Import data -> wizard will open
click on Next(Source wizard will open) and choose the "Microsoft Excel" option in DataSource dropdown and choose the excel path Click the "Next" button(Excel column and Table column should be same otherwise it won't insert).
enter destination details in the wizard,click on Next
click the Next button
Click the Next button and Finish

SQL Server Management Studio can do this via its Import / Export features. I do this routinely using SSMS.
In SSMS, right click on your database, then choose Tasks | Import Data.

You first need to import the Excel sheet into your database. Then Use a query to update your table.

You can use SQL Server Import and Export Wizard
First import the data from excel to a temporary table (It will create new table, which you can drop later)
Once you have the data in a table, then you can update your existing one
Here is a simple step by step approach

try this one
Option Explicit
Public CN As ADODB.Connection
Dim Cod_Prod, Nombre, Existencia
Dim Fila, Final As Integer
Function Connect(Server As String, User As String, Pass As String, Database As String) As Boolean
Set CN = New ADODB.Connection
On Error Resume Next
With CN
.ConnectionString = "Provider=SQLOLEDB.1;" & _
"Password=" & Pass & ";" & _
"Persist Security Info=True;" & _
"User ID=" & User & ";" & _
"Initial Catalog=" & Database & ";" & _
"Data Source=" & Server
.Open
End With
If CN.State = 0 Then
Connect = False
Else
Connect = True
End If
End Function
Function Query()
Dim SQL As String
Dim RS As ADODB.Recordset
Dim Field As ADODB.Field
Dim Col As Long
Set RS = New ADODB.Recordset
Final = GetUltimoR(Hoja1)
For Fila = 2 To Final
Cod_Prod = Hoja1.Cells(Fila, 2)
Nombre = Hoja1.Cells(Fila, 3)
Existencia = Hoja1.Cells(Fila, 4)
SQL = "insert into productos values('" & Cod_Prod & "','" & Nombre & "'," & Existencia & ");"
RS.Open SQL, CN
Next
RS.Open "SELECT * FROM PRODUCTOS", CN
If RS.State Then
Col = 1
For Each Field In RS.Fields
Cells(1, Col) = Field.Name
Col = Col + 1
Next Field
Cells(2, 1).CopyFromRecordset RS
Set RS = Nothing
End If
End Function
Function Disconnect()
CN.Close
End Function
Public Sub run()
Dim SQL As String
Dim Connected As Boolean
Connected = Connect("192.168.0.12", "usuario1", "12345", "inventario")
If Connected Then
Call Query
Call Disconnect
Else
MsgBox "No podemos Conectarnos!"
End If
End Sub
Public Function GetUltimoR(Hoja As Worksheet) As Integer
GetUltimoR = GetNuevoR(Hoja) - 1
End Function
Public Function GetNuevoR(Hoja As Worksheet) As Integer
Dim Fila As Integer
Fila = 2
Do While Hoja.Cells(Fila, 2) <> ""
Fila = Fila + 1
Loop
GetNuevoR = Fila
End Function

BULK INSERT [Trading].[dbo].[tmp_mst_bhavcopy]
FROM 'E:\Text\bhavcopy.csv'
WITH (
FIELDTERMINATOR=',',
ROWTERMINATOR = '0x0a',
firstrow=2
)

Related

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.

Loop to insert multiple values into SQL Server

I am trying to insert a lot of values into SQL Server in one SQL insert statement. So for example..
Insert Into someDataBase
Values(value1, value2, value3,..., value120, value121)
All these values will be in the correct order on a sheet in Excel. I already created a loop to go through all the 121 values but I can't think of a loop for the inserting the values without writing each value individually.
Can anyone help me out?
My code looks like this:
Sub AddRows()
' In VBE you need to go Tools References and check Microsoft Active X Data Objects 2.x library
Dim Cn As ADODB.Connection
Dim Server_Name As String
Dim Database_Name As String
Dim User_ID As String
Dim Password As String
Dim SQLStr As String
Dim comm As ADODB.Command
Set comm = New ADODB.Command
Dim param As ADODB.Parameter
Dim getType As String
SQLStr = "Insert Into [DB] Values("
For i = 1 To 121
'Get type
getType = CellType(i, Cells(2, i))
SQLStr = SQLStr & "?,"
Set param = New ADODB.Parameter
param.Name = "Param" & i
Set param = comm.CreateParameter("param" & i, getType, adParamInput, 1000)
param.Attributes = adParamNullable
Debug.Print (param.Type)
comm.Parameters.Append param
Next i
SQLStr = Left(SQLStr, Len(SQLStr) - 1) & ");"
Set Cn = New ADODB.Connection
Cn.CommandTimeout = 0
Cn.Open "Driver={SQL Server};Server=" & Server_Name & ";Database=" & Database_Name & _
";Uid=" & User_ID & ";Pwd=" & Password & ";"
comm.ActiveConnection = Cn
comm.CommandText = SQLStr
comm.CommandType = adCmdText
Dim test As String
lastrow = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row
'For x = 2 To lastrow
For i = 1 To 121
Debug.Print (Cells(2, i).Value)
comm.Parameters.Item("Param" & i).Value = Cells(2, i).Value
Next
comm.Execute
'Next x
Cn.Close
Set Cn = Nothing
End Sub
This is a portion of my CellType Function:
Private Function CellType(Num) As MultipleValues
Application.Volatile
CellType.CellNum = 50
Select Case True
Case Num = 1
CellType.CellType = adInteger
Case Num = 2
CellType.CellType = adInteger
Case Num = 3
CellType.CellType = adVarWChar
CellType.CellNum = 255
Case Num = 4
CellType.CellType = adCurrency
Case Num = 5
CellType.CellType = adVarWChar
CellType.CellNum = 255
The values for the first 5 values are: 0, null, 6071/1, 44.5, Biltmore Fleur De Lis Collection Authentic Wrought Iron
It breaks on the second value which is a null but should be an integer.
I would generally agree that using an SSIS package would be the best way to approach this, but if you want to do it through code, it's not difficult with a parameterized query in ADODB:
Use the ? placeholder for parameters when you're building your INSERT statement, and add parameters to an ADODB.Command object:
Dim comm As ADODB.Command
Set comm = New ADODB.Command
Dim param As ADODB.Parameter
SQLStr = "Insert Into [db] Values("
For i = 1 To 121
SQLStr = SQLStr & "?,"
Set param = New ADODB.Parameter
param.Name = "Param" & i
comm.Parameters.Append param
Next i
SQLStr = Left(SQLStr, Len(SQLStr) - 1) & ");"
When you're done, you'll have a matched set of parameters and placeholders.
Then open your connection (or do it before this, it really doesn't make much difference) and set up the command:
comm.ActiveConnection = Cn
comm.CommandText = SQLStr
comm.CommandType = adCmdText
Finally, loop through your rows for each record, loop through the values and assign them to parameters, and execute for each row:
lastrow = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row
For x = 2 To lastrow
For i = 1 To 121
comm.Parameters.Item("Param" & i).Value = Cells(x, i).Value
Next
comm.Execute
Next x
Note that ADODB Commands are optimized to be looped over - the backend treats this more like a batch insert, so there isn't really much point in trying to build a gigantic insert will all the records in it at once.
Don't know if the excel spreadsheet has special formatting, but if its in a CSV format, you can use SQL Server Import and Export Wizard to do this. Here's how:
In SQL Server Management Studio, login to your database server.
Right click the database you want to import data into and select Task -> Import Data
Import Data Image
On the Choose Data Source screen, choose Microsoft Excel from the Data Source drop down. Enter the file path to the excel spreadsheet in Excel file path. Select the appropriate Excel version in Excel version. If the first row in the spreadsheet contains the database column names, check the First row has column names. If it's just data, uncheck it.
Choose Data Source Image
Click Next and choose Microsoft OLE DB Provider for SQL Server in the Destination drop down. Select your sql server name in Server name drop down. Choose Authentication option. Click Refresh, then choose the database you want to insert the Excel data into.
On the Specify Table Copy or Query window, select Copy data from one or more table or views. Click Next.
Select the check box next to Sheet1$ in the Source column. Click in the Destination column and select the table you want to import the Excel data into. Clicking the Preview button will show the query and how the data will look in the new table. Click Next.
The mapping should be good on the Review Data Type Mapping page. This window allows you to setup options on what SQL should do in regards to converting. Defaults should be fine. Click Next.
Click Next. The import should run immediately.
Review the summary page and click Finish.
The import will perform several operations. Green check marks indicate that the operation was successful. Read circles with X's indicate failure. If you get a failure, post an image of it here with your data and the hyperlinked message from the Message column.
If you want, you can check out the bulk insert command as well on MSDN. I don't have enough rep to post more images. I'll finish it later when I have enough.

Read a value via ADO in an Excel file before changing it

I learned a couple of weeks ago how to update an Excel file via ADO. At that time the value was already given before changing it.
Now I want to add the procedure of reading the current value in the same cell and assign the value to a variable before changing it!
The current procedure looks as follows:
Public Sub ChangeNum()
Dim con As ADODB.Connection, rec As ADODB.Recordset
Dim sqlstr As String, datasource As String
Set con = New ADODB.Connection: Set rec = New ADODB.Recordset
datasource = "D:\DropBox\TraderShare\TraderNum.xlsx"
Dim sconnect As String
sconnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & datasource & ";" & _
"Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
con.Open sconnect
sqlstr = "UPDATE [Sheet1$] SET [Number] = """ & gsvDocNum & """ WHERE [ID] = """ & svNumRng & """"
rec.Open sqlstr, con ', adOpenUnspecified, adLockUnspecified 'adLockOptimistic , adOpenStatic, adLockReadOnly
con.Close
Set rec = Nothing: Set con = Nothing
End Sub
gsvDocNum is a global string variable declared in the beginning of the initial startup routine, hence after reading the current value into the variable, the UPDATE one will write gsvDocNum + 1 to the file.
svNumRng is one of the following named ranges, PNum, SNum, TNum or INum declared in the beginning of the main routine and determined which one to look for in an earlier stage (if it’s an Purchase, SalesOrder, TradeOrder or an Invoice).
I’m not so familiar with ADO and SQL strings and I can’t find the proper syntax for SELECT for reading the current cell value and assign it to a variable before changing it with the UPDATE.
Grateful for any help!
OK, the background as follows: We have an administrative program I’ve written myself in Excel vba for registering purchases, orders and invoices, etc. It works pretty well for our requirements but has one issue, keeping order numbers synced between the users! We are 3 users using the program locally, each one registering orders and such, but we share the serial number file via a shared DropBox folder. I have the idea that using ADO/SQL without opening the Excel file would be faster than open, change and save the file in Excel. The reason is of course to minimize the time updating the file thus the delay before syncing to the cloud Dropfox location and to the other users computers is minimized. It’s a simple 2 column Excel file, TraderNum.xlsx:
ID Number
PNum 16000
SNum 16000
TNum 16132
INum 16173
I learned a couple of weeks ago how to change one of the numbers from Excel without opening the file using ADO/SQL, (see above). But I discovered that a constant update of the Excel link to a closed file for having the current number available before changing it doesn’t work as expected. Accordingly I want to use ADO/SQL also to read/assign the specific current number to a variable in the Excel procedure, before changing it with the ADO/SQL procedure above.
So somewhere between the 2 commands, rec.Open sconnect and con.Close there should be a SQL-string similar to:
sqlread = "SELECT """ & DocNumOld & """ = [Number] FROM [Sheet1$] Where [ID] = """ & svNumRng & """"
where the DocNumOld variable is assigned the current number from the chosen ID variable svNumRng.
Then the DocNumNew variable is and assigned with the DocNumOld variable incremented with 1 followed by the
sqlUpdate sequence. It should look similar to the following:
Public Sub ChangeNum()
Dim con As ADODB.Connection, rec As ADODB.Recordset
Dim sqlRead as String, sqlUpdate As String, datasource As String, sconnect As String
Set con = New ADODB.Connection: Set rec = New ADODB.Recordset
datasource = "D:\DropBox\TraderShare\TraderNum.xlsx"
sconnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & datasource & ";" & _
"Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
con.Open sconnect
sqlRead = "SELECT """ & DocNumOld & """ = [Number] FROM [Sheet1$] Where [ID] = """ & svNumRng & """"
sqlUpdate = "UPDATE [Sheet1$] SET [Number] = """ & DocNumNew & """ WHERE [ID] = """ & svNumRng & """"
rec.Open ???????, con
????? sqlRead
DocNumNew = DocNumOld + 1
UNION
????? sqlUpdate
con.Close
Set rec = Nothing: Set con = Nothing
End Sub
Can you solve this, please?
Can anyone give me a solution to how to use ADO/SQL also to read/assign one specific current number to a variable in an Excel procedure, before changing it with the ADO/SQL procedure?
I am concerned I don't understand your question, because the resulting comments don't make sense to me.
To restate your problem: you need to know the value of some cell, and be able to feed it into your code.
You can already connect to a worksheet with SQL, you already know what SELECT statements are, and you probably already know how to run them. Humor me.
sqlRead = "SELECT * FROM [Sheet1$A12:F48]"
Set rec = con.Execute(sqlRead)
Now you have a recordset rec that contains the whole table. Say you wanted to put every value of the entire table in your immediate window:
Do While Not rec.EOF
For i = 0 To rec.Fields.Count - 1
Debug.Print rec.Fields(i).Name, rec.Fields(i).Value
Next
rec.MoveNext
Loop
Don't forget to close it, and I suggest using a second variable name anyway as the name of the recordset for the update statement.
rec.Close
Say you knew the cell would always be in the 3rd row, 8th column of the table you are selecting from, you might:
For j = 0 to myRowNum-1 'you have set myRowNum equal to 3 earlier'
rec.MoveNext
Next
myOldCellValue = rec.Fields(myColNum-1).value 'you have set myColNum to 8 earlier'
rec.Close
Now, say you don't know exactly which row you will find myOldCellValue, but you know it will be found in the 4th column of the row that has the unique [ID] 1234, you might:
sqlRead = "SELECT * FROM [Sheet1$A12:F48] Where [ID] = """ & myIDNum & """" 'you have set myIDNum to 1234 earlier
Set rec = con.Execute(sqlRead)
myOldCellValue = rec.Fields(myColNum-1).value 'you have set myColNum to 4 earlier'
rec.Close
Say you wanted to UPDATE every row that had that value (I don't read that you, but for completeness), you might:
sqlUpdate="UPDATE [Sheet1$] SET [Number] = """ & DocNumNew & """ WHERE [DocNum] = """ & myOldCellValue & """"

Excel VBA Array not receiving all values from stored procedure recordset - different result than running stored procedure outside of Excel

I have quite a conundrum which I have been trying to troubleshoot. I have a stored procedure in a MySql database, which I call through an Excel VBA application. The VBA application passes the recordset into an Array, and then I use a For Loop to place each of the items in the Array onto a worksheet.
Here's the problem: two of the values in the recordset keep coming back blank in Excel. Oddly, the two are in the middle of the Array, not the beginning or end. However, if I call the stored procedure through another query program such as HeidiSql, I receive ALL values back. I'm at a loss as to why I'm not receiving all of the values through Excel... or why the Array isn't receiving them all, at any rate.
Thanks in advance for your help.
Here is my code:
Sub StartHereFlexFunderCust()
On Error GoTo ErrorHandler
Dim Password As String
Dim SQLStr As String
'OMIT Dim Cn statement. Cn stands for Database Connection
Dim Server_Name As String
Dim User_ID As String
Dim Database_Name As String
Dim custID As String
Dim myArray()
'OMIT Dim rs statement. rs stands for Database Recordset and is the Recordset of what is returned
Set RS = CreateObject("ADODB.Recordset")
Server_Name = Range("O10").Value
Database_Name = Range("O11").Value ' Name of database
'id user or username. We need to write code to insert the current user into this variable (Application.Username) if possible. But they may not be consistent across all machines.
'For example mine is "Ryan Willging" and we would have to shorten it to rwillging but others may be rwillging.
'This is important because if we do not do this all queries will come from the same person and that is not good for debugging.
User_ID = Range("O12").Value
Password = Range("O13").Value
custID = Range("C4").Value 'Deal Number from Start here that we are passing into the stored procedure
'This is the storedprocedure call and it passes in the value of the DealId to the Stored Procedure
SQLStr = "call flexFundByCustomer(" + custID + ")"
Set cn = CreateObject("ADODB.Connection") 'NEW STATEMENT
'This statement takes the variables from the checklist and passes them into a connection string
cn.Open "Driver={MySQL ODBC 5.1 Driver};Server=" & _
Server_Name & ";Database=" & Database_Name & _
";Uid=" & User_ID & ";Pwd=" & Password & ";"
'This statement queries the database using the SQL string and the connection string.
'The adOpenStatic variable returns a static copy of a set of records that you can use to find data or generate reports. There are other variables that
'could be used but I think this one will suffice.
RS.Open SQLStr, cn, adOpenForwardOnly
Debug.Print msg 'or MsgBox msg
'Take all of the info from the queries and put them into the spreadsheet
myArray = RS.getrows()
Dim Fld_Name As String
Dim Val_of_Field As String
Dim starthere As Worksheet
Fld_Name = UBound(myArray, 1)
Val_of_Field = UBound(myArray, 2)
Set starthere = ThisWorkbook.Sheets("Start Here")
MsgBox "No error yet defined Start Here!"
'This little loop works well to dump the recordset into excel. We can then map the correct fields 'k inputs the headers and R inputs the rows returned in the Recordset
For K = 0 To Fld_Name ' By using a For loop the data is inputed into excel one row at a time
starthere.Range("U4").Offset(0, K).Value = RS.fields(K).Name
For R = 0 To Val_of_Field
starthere.Range("U4").Offset(R + 1, K).Value = myArray(K, R)
Next
Next
RS.Close
Set RS = Nothing
cn.Close
Set cn = Nothing
ErrorHandler:
MsgBox "There's been an error!"
Exit Sub
End Sub
Consider using Range.CopyFromRecordset method to avoid any use of arrays. Or if memory does not allow, use a Do While Loop across Recordset columns:
' COLUMN HEADERS
For i = 1 To RS.Fields.Count
starthere.("Results").Range("U4").Offset(0, i) = RS.Fields(i - 1).Name
Next i
' DATA ROWS
' COPYFROMRECORDSET APPROACH
starthere.Range("U5").CopyFromRecordset RS
' DO WHILE LOOP APPROACH
starthere.Activate
starthere.Range("U5").Activate
row = 5
Do While Not RS.EOF
For i = 0 To RS.Fields.Count - 1
ActiveCell.Offset(0, i) = RS.Fields(i)
Next i
row = row + 1
ActiveCell.Offset(row, 21)
RS.MoveNext
Loop
As for the values returning empty that may be a MySQL and Excel incompatibility of data types. For instance, you may have a table field set to MySQL's maximum decimal (65, 30) which denotes max digits of 65 and max 30 decimal points which cannot be reflected on a spreadsheet. Current precision limit of a cell value is 15 decimal points.
Alternatively, you may have a VARCHAR(65535) which is the 65,535 byte limit or the open-ended TEXT column of no limit that also cannot be displayed on spreadsheet. Current limit of characters in one cell is 32,767.
Try modifiying column to a smaller type:
ALTER TABLE `tableName` MODIFY COLUMN `largenumberfield` DECIMAL(10,7);
ALTER TABLE `tableName` MODIFY COLUMN `largetextfield` VARCHAR(255);
Why the other programs such as HeidiSQL retrieve values? It might be due to their internal conversion features forcing data values into a specific format (i.e., removing whitespaces, truncating values) which then renders adequately in Excel.

Reading over 254 columns from an Excel 2010 file using ACE SQL server

I am using the connection string
szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & fpath & fname & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"";"
Set rsData = New ADODB.Recordset
'Run the query as adCmdText
rsData.Open szSQL, szConnect, adOpenForwardOnly, adLockReadOnly, adCmdText
'Check if data exists for query
If Not rsData.EOF Then
rtnArr = rsData.GetRows 'if the recordset contains data populate the array
Else
dEmp = True 'no data flag true
ReDim rtnArr(0 To 0, 0 To 0)
End If
to run SQL queries in VBA from an external Excel 2010 file. The file has over 40 sheets and each sheet is approx. 369 columns wide, currently the SQL is only returning the first 255 columns of data as per the SQL server limitations. A number of forums discussing this problem suggest transforming the workbook into a flat (.csv) however this wouldn't be ideal. Does anyone have an alterative solution to this? Or a way of forcing through the extra columns?
Thanks!
ADO has a limit of 255 fields when connecting to Excel. (see here for limitations - ACE/JET/Access are intricately linked)
Your best bet would be to try opening the excel file as an excel file, and reading the cells to create an insert statement
Dim xlApp As Object
Dim OWorkbook As Object
Set xlApp = CreateObject("Excel.Application")
Set OWorkbook = xlApp.workbooks.Open("MyFile.xlsx")
With OWorkbook.Worksheets(1)
c1 = .Cells(RowCount, 1).value
...
c290 = .Cells(RowCount, 290).value
Then construct the Insert
strInsertSQL = "INSERT INTO [MyDB].[dbo].[MyTable] ([Val1],[Val2],...,[Val290])"
strSQLValues = " VALUES (" & c1 & ", '" & c2 & "'," & ... & c290 & ")"
cmd.ActiveConnection = "Provider=SQLNCLI11;Server=MyServer;Database=MyDB"
cmd.CommandText = strInsertSQL & strSQLValues
cmd.CommandTimeout = 0
cmd.Execute 'strInsertSQL & strSQLValues
Increment RowCount as needed

Resources