Loop to insert multiple values into SQL Server - 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.

Related

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 to SQL Index and Seek

I am exporting data in Excel table to SQL Server Database, If exists UPDATE else INSERT.
The following VBA code works well for exporting to ACCESS Database,
BUT NOT TO SQL SERVER DATABASE TABLE.
Error Message appear :Invalid Use of Property for .Index and .Seek.
Please Help !!! Toh
Sub ExcelDataToSql ()
Dim cn As ADODB.Connection, rs As ADODB.Recordset, r As Long
Dim lastrow As Long, o As Long
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
cn.Open "Provider=SQLNCLI11;Server=***;Database=****;Trusted_Connection=yes;"
rs.CursorLocation = adUseServer
rs.Open "InventorySQL", cn, 1, 3, adCmdTableDirect
' Get Lastrow
Worksheets("InventoryEXCEL").Select
lastrow = Worksheets("InventoryEXCEL").Cells(rows.Count, 1).End(xlUp).Row
r = 2 ' the start row in the worksheet
For o = 2 To lastrow
'Check For Duplicate In Database SQL
With rs
.Index = "PrimaryKey"
.Seek Range("A" & r).Value
If .EOF Then
.AddNew
'If No Duplicate insert New Record
rs.Fields("oPartno") = Range("A" & r).Value
rs.Fields("oDesc") = Range("B" & r).Value
rs.Fields("oCost") = Range("C" & r).Value
.update
Else
' If Duplicate Found Update Existing Record
rs.Fields("oDesc") = Range("B" & r).Value
rs.Fields("oCost") = Range("C & r).Value
.Update
End If
End With
Next o
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
MsgBox "Posting Completed"
End Sub
. Index = "PrimaryKey" --- Sysntax Error : Invalid Use of Property
.Seek Range ("A" & r).Value Sysntax Error :
Reference:Seek Method and Index Property Example (VB)
The MSDN example passes an Array as the first parameter.
rstEmployees.Seek Array(strID), adSeekFirstEQ
The first parameter's name os KeyValues which also implies an array
I would try this first
.Seek Array(Range("A" & r).Value)
It might also be beneficial to use one of the SeekEnum value
Update: TOH the OP found that this was the relavent code snippet
MSDN also suggest checking if the Provider supports .Index and .Seek
If rstEmployees.Supports(adIndex) And rstEmployees.Supports(adSeek) Then
My Problem is resolved by work around.
Many resources indicated that Sql Providers do not support the index and seek function. So I avoid Index and Seek
I work around by importing the excel worksheet into Sql server as source table... thereafter Merge the target table with source table... if match UPDATE, if Not Match INSERT.
select * from InventoryTableSQL
select * from InventoryTableFromExcel
Merge InventoryTableSQL as T
using InventoryTableFromExcel as S
on t.oPartno = s.oPartno
when matched then
update set t.oPartno = s.oPartno,
t.oDesc = s.oDesc,
t.oCost = s.oCost
when not matched by target then
insert(oPartno, oDesc, oCost) values(s.oPartno, s.oDesc, s.oCost));

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.

Insert Data into SQL Table from an Excel Sheet

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
)

Update Access 2003 MDB to point to a different SQL Server database

Access 2003 / SQL Server - how can I update Access 2003 MDB (Connect property) to point to a different SQL Server database? The new SQL Server database is on the same instance as the old one.
I have several MS Access 2003/SQL Server applications that I manage. All of them dynamically attach to the correct database at startup. Some of them even connect to multiple databases on different servers during the start up sequence. All of them use the same basic vba routine to actually dynamically attach a table to the correct server. This is not my code, I found it by googling around the internet, but I have lost the reference to it now, so apologies in advance to the authors.
Before showing the code, to put it in context, I normally have a form "frmInitApp" with a data source that is a local config table, with a field named "ID". I start the access application from the AutoExec macro which opens this form with a filter of "ID=1". I have other forms to manipulate this config table and change the IDs around, so to switch between production and test I just change which entry has ID=1.
I also have another local table, tableList, with a list of Access tables that I want to connect dynamically to a SQL Server. Most applications have another field in this table for the SQL Server table name (so they don't have to be the same) - some applications have an additional field to specify which database. But the more complex the more other spaghetti you need - I often end up with another table of connection strings to all the separate databases I might connect to etc etc. To keep it simple just have the connection string in a field in the config table that is the datasource to frmInitApp.
We get started with the current event on frmInitApp.
Private Sub Form_Current()
If Me.Filter = "" Then 'If nobody has told us what record to use then use id=1
Me.Filter = "[ID]=1"
configID = 1
Else
configID = CInt(Mid(Me.Filter, 6)) 'We are assuming the load criteria are "[ID]=..."
End If
Me.messages = "Connecting to databases ..."
DoCmd.Hourglass True
Me.stage = "InitialStartup" 'Set the stage which is to be executed during timer phase
Me.TimerInterval = 100 'We set the time to go off to so we can let autoexec finish and let us control focus
End Sub
and then in the timer we can link to the tables via an attach table function with I'll put further down the answer. Note also that we relink pass through queries as well so they point to the new database also. Also note that we start Open a new form a login one fore users as soon as we have attached to the first table. I don't show the conclusion where will probably have to validate username and password against the attached table when its all done, but its trivial to figure out anyway.
Private Sub Form_Timer()
Dim conn As ADODB.Connection
Dim dbRs As ADODB.Recordset
Dim dbOK As Boolean
Dim SQL As String
Dim startedLogon As Boolean
Me.TimerInterval = 0
Select Case Me.stage
Case "InitialStartup"
Set conn = CurrentProject.Connection
startedLogon = False
If CurrentProject.AllForms("frmLogon").IsLoaded Then
'If its already loaded this NOT the first time through, but still need to logon ...
If Form_frmLogon.configID = configID Then
startedLogon = True 'unless its the same config
End If
End If
dbOK = True
Set dbRs = New ADODB.Recordset
dbRs.Open "SELECT localname,servername FROM tableList", conn
While dbOK And Not dbRs.EOF
'PLEASE NOTE - WHILST THEORETICALLY "localname" and "servername" could be different the migration process
'requires that they be the same. Do not consider changing this until after migration is completed
dbOK = AttachTable(dbRs("localname"), "dbo." & dbRs("servername"))
dbRs.MoveNext
If Not startedLogon And dbOK Then
DoCmd.Close acForm, "frmLogon" '#554 Just in case its alread open - we need to pick up new params
DoCmd.OpenForm "frmLogon", , , , , , Nz(Me.lastUserId, "") & ":" & configID
Form_frmLogon.SetFocus '#748 Give it focus
startedLogon = True
End If
Wend
dbRs.Close
If dbOK Then
Me.messages = "Relinking Common Queries ..."
DoEvents
Dim qd As DAO.QueryDef, cs As String
cs = getStrConnDAO 'get the DAO connection string
For Each qd In CurrentDb.QueryDefs
If Len(qd.Connect & vbNullString) > 0 Then
qd.Connect = cs
End If
Next
End If
Me.messages = "Awaiting User Log On"
DoCmd.Hourglass False
DoEvents
... the rest just managing logon
End Sub
The attached table function
'//Name : AttachTable
'//Purpose : Create a linked table to SQL Server without using a DSN
'//Parameters
'// stLocalTableName: Name of the table that you are creating in the current database
'// stRemoteTableName: Name of the table that you are linking to on the SQL Server database
Private Function AttachTable(stLocalTableName As String, stRemoteTableName As String)
Dim td As TableDef
Dim stConnect As String
Me.messages = "Connecting to Database Table " & Me.mainDatabase & "." & stRemoteTableName
DoEvents
On Error Resume Next
CurrentDb.TableDefs.Delete stLocalTableName
If Err.Number <> 0 Then
If Err.Number <> 3265 Then GoTo AttachTable_Err 'v4.0.44 - allow delete errors
Err.Clear
End If
On Error GoTo AttachTable_Err
Set td = CurrentDb.CreateTableDef(stLocalTableName, dbAttachSavePWD, stRemoteTableName, getStrConnDAO(configID))
CurrentDb.TableDefs.Append td
DoEvents
AttachTable = True
Exit Function
AttachTable_Err:
AttachTable = False
errMsg = "AttachTable encountered an unexpected error: " & Err.description & " on table " & stRemoteTableName & " in database " & Me.mainDatabase
End Function
You will need to getConStrDAO function
Private ADOconnStr As String
Private DAOconnStr As String
Public Function getStrConn(Optional configID As Long = 0) As String
'create a connection string for use when running stored procedures
'this uses the saved value if possible, but global variables are reset if an error occurs
If ADOconnStr = "" Then
Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim account As String
Dim revealedPassword As String
Dim s As String, i As Integer, x As String
Set conn = CurrentProject.Connection
If configID = 0 Then configID = Nz(Form_frmLogon.configID, 0)
Set rs = conn.Execute("SELECT * FROM localConfig WHERE id =" & configID)
If Not rs.EOF Then
ADOconnStr = "Provider=Microsoft.Access.OLEDB.10.0;Data Provider=SQLOLEDB;SERVER=" 'this provider is needed to allow use of SP as form.recordset
ADOconnStr = ADOconnStr & rs("ServerName") & ";DATABASE=" & rs("DatabaseName") & ";UID="
ADOconnStr = ADOconnStr & rs("dbUser") & ";PWD=" & EncryptDecrypt(Nz(rs("dbPassword"), ""))
End If
rs.Close
Set rs = Nothing
Set conn = Nothing
End If
getStrConn = ADOconnStr
End Function
Public Sub resetConnection()
ADOconnStr = ""
DAOconnStr = ""
End Sub
Function getStrConnDAO(Optional configID As Long = 0) As String
If DAOconnStr = "" Then
Dim a As New ADODB.Connection
a.Open getStrConn(configID)
DAOconnStr = "ODBC;driver=SQL Server;" & a.Properties("Extended Properties") & ";"
Set a = Nothing
End If
getStrConnDAO = DAOconnStr
End Function
And finally a simple encryption of database password to make it not obvious to casual eyes - something again copied from the internet
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''' Comments: Performs XOr encryption/decryption on string data. Passing a
''' string through the procedure once encrypts it, passing it
''' through a second time decrypts it.
'''
''' Arguments: szData [in|out] A string containing the data to
''' encrypt or decrypt.
'''
''' Date Developer Action
''' --------------------------------------------------------------------------
''' 05/18/05 Rob Bovey Created
'''
Public Function EncryptDecrypt(szData As String) As String
Const lKEY_VALUE As Long = 215
Dim bytData() As Byte
Dim lCount As Long
bytData = szData
For lCount = LBound(bytData) To UBound(bytData)
bytData(lCount) = bytData(lCount) Xor lKEY_VALUE
Next lCount
EncryptDecrypt = bytData
End Function

Resources