Trying to create a table in excel via VBA and OLEDB - vba

I am trying to create a table (tab) in Excel using VBA with ADODB. Could you tell me where I am going wrong?
I get an error at comm.Execute after the comm.CommandText = "create table [temptable]([AA] VARCHAR(40));" line:
Microsoft Access database engine could not find the object 'temptable'.
Adding a $ at the end of the table name or a # at the beginning does not seem to help.
Sub sqlquery2()
Dim rs As ADODB.Recordset
Dim conn As String
Dim conObj As ADODB.Connection
Dim comm As ADODB.Command
Dim fileName As String
Set conObj = New ADODB.Connection
Set comm = New ADODB.Command
fileName = ThisWorkbook.FullName
conn = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & fileName & ";" & _
"Extended Properties=Excel 12.0 XML"
conObj.ConnectionString = conn
conObj.Open
comm.ActiveConnection = conObj
comm.CommandType = adCmdText
On Error Resume Next
comm.CommandText = "DROP TABLE [temptable];"
comm.Execute
On Error GoTo 0
comm.CommandText = "create table [temptable]([AA] VARCHAR(40));"
comm.Execute
comm.CommandText = "insert into [temptable] select [A] from [SQL_Test$];"
comm.Execute
conObj.Close
End Sub
Thank you very much in advance!

Try doing it on a closed workbook.
I've had this problem with an open workbook. It disappeared when I did it on a closed workbook. It was also crashing telling me the table (worksheet) did not exist when the wbk was open. The worksheet did exist. This problem also disappeared when I queried a closed wb.

Related

How do I make a db connection to Excel that more than one user can open at same time?

You've help me to get to this point and now I'm stuck again. The macro works fine, but only one person can run it at any given time. If two users try to run it at the same time, they get a Runtime error. When I click Debug, it takes me to "myConn.Open"
To clarify, I'm not trying to allow multiple users to edit the Excel spreadsheet. They are only opening it read-only to get values from it, not to add or edit it in any way.
Public Sub Letter()
Dim rngStory As Word.Range
Dim rngCount As Long
Dim mySQLquery As String
Dim myKey As String
Dim mySource As String
Dim slkAddresseeName, slkRegarding, slkFileNum, slkSalutation As String
Dim slkTemplate As String
Dim myConn As ADODB.Connection
Dim myRs As ADODB.Recordset
Dim slkTempDoc As String
' Prompt user for Login ID
myKey = InputBox("Enter Attorney or Paralegal LOGIN ID (e.g., jtorres or b324):")
' Make DB connection
mySQLquery = "SELECT * FROM [All_Users$] WHERE LoginID = '" & myKey & "'"
mySource = "\\servername\vol1\macros\master\LetterMemoDB.xlsx"
Set myConn = New ADODB.Connection
Set myRs = New ADODB.Recordset
With myConn
.Provider = "Microsoft.ACE.OLEDB.12.0;Data Source=" & mySource & ";Extended Properties=""Excel 8.0;HDR=YES"";"
End With
myConn.Open
myRs.Open mySQLquery, myConn, adOpenStatic, adLockReadOnly
' End of DB connections
My guess is I'm using ACE as the provider and maybe it can't support multiple, simultaneous connections. What's the fix?
Fix was to change the Excel file to read-only via right click | Properties. Sorry for the stupid question.

How to connect to Netezza (PureData System for Analytics) via VBA

I am trying to connect to connect to Netezza using VBA. I have enabled the following:
Microsoft Excel 15.0 Object Library
Microsoft Office 15.0 Object Library
Microsoft ActiveX Data Objects 6.1 Library
Visual Basic for Applications
Here is my code:
Sub NZConn()
Dim cmd As New ADODB.Command
Dim rs As New ADODB.Recordset
Dim x As Variant
Set cmd = New ADODB.Command
Set RS = New ADODB.Recordset
cmd.ActiveConnection = "Driver={Netezza " & _
"ODBC};servername=servername;port=####;database=database;" & _
"username=username;password=password;"
cmd.ActiveConnection.CursorLocation = adUseClient
cmd.CommandTimeout = 120
cmd.CommandType = adCmdText
x = "Write Query here"
cmd.CommandText = x
Set rs = cmd.Execute
Sheet1.Range("A1").CopyFromRecordset rs
cmd.ActiveConnection.Close
End Sub
I can get the code to run without throwing back an error, but there is nothing that is pasted from the record set, which leads me to believe that is may have something to do with the structure of the connection string.
I have the server, user id, password, database, port, and driver.
Would I need to establish / open an ActiveConnection first?
I was able to figure out the issue on my own. I found that there is a command line builder in the 'Tools' tab in Aginity, which helped specify the exact connection string I needed to connect to Netezza. Once I had this connection string, I was getting an 'architecture mismatch' error. After downloading the 32-bit ODBC drivers for Netezza, the methodology worked perfectly. Here is the updated code below:
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim iCols As Integer
Dim DB As String, User As String, PW As String, ConnectionString As String
Dim Server As String, Query As String
Dim SQLTable As Worksheet
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
Set SQLTable = Sheet1
Server = SQLTable.Cells(2,3).Value
User = SQLTable.Cells(2,4).Value
PW = SQLTable.Cells(2,5).Value
DB = SQLTable.Cells(2,6).Value
Query = SQLTable.Cells(2,7).Value
ConnectionString = "Driver={NetezzaSQL};" & _
"server=" & Server & ";" & _
"UserName=" & User & ";" & _
"Password=" & PW & ";" & _
"Database=" & DB & ";" & _
"Query Timeout=120"
cn.Open (ConnectionString)
rs.Open (Query), cn
For iCols = 0 To RS.Fields.count - 1
Worksheets("Sheet2").Cells(1, iCols + 1).Value = rs.Fields(iCols).Name
Next
Worksheets("Sheet2").Cells(2, "A").CopyFromRecordset rs
rs.Close
cn.Close
NB:
"IBM NETEZZA ODBC DRIVER – 32 BIT" is what I downloaded
"ODBC-DRIVER-FOR-NETEZZA-7-X86" is what showed up in my software center to install
"Name: NetezzaSQL ; Version: 7.00.04.41188 ; Company: www.ibm.com ; File: NSQLODBC.DLL" is what is shown now in my 32-bit 'ODBC Data Source Administrator' window
I think your connection string is ok, and yes you should need to open a connection first.
Like this:
AccessConnect = "Driver={Netezza " & _
"ODBC};servername=servername;port=####;database=database;" & _
"username=username;password=password;"
Dim Conn1 As New adodb.Connection
Conn1.ConnectionString = AccessConnect
Conn1.Open
then it would be
Set RS = Conn1.Execute(x) 'where x is your query

How to export SQL statement results to an Excel File

I have an Access DataBase and a form in Excel VBA. All the data I input into the DB is input through the VBA form.
This DB contains all the benefits cards we already received this year in the company. But the same employee can ask for the card twice or more, so we'll have more than one record on the DB for him.
What I need is when the number of records is greater than one, the SQL statement result should appear in a Excel report.
I use the SELECT (*) COUNT statement to know when there is more than one record that is compatible with the search criterion. But I can't make the result appear in an Excel file.
Here is my code:
Public Function Relatorio()
Dim sql As String
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim rel As String
Set cn = New ADODB.Connection
cn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & enderecoDB & ";Jet OLEDB:Database"
cn.Open
Set rs = New ADODB.Recordset
sql = "INSERT INTO OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0;Database=" & enderecoDB & ";', 'SELECT * FROM [Planilha1$]') SELECT * FROM controle WHERE BP = " & controlectform.nmbpbox.Value & ";"
rs.Open sql, cn
End Function
When I run this code it gives me a message saying something like:
Can't locate the OPENROWSET Table exit
I'm not able to install new programs, so I need to do this using only Excel VBA and the Access DB.
How can I make this work?
I don't believe Access supports the OPENROWSET, dynamic table you're working with there. I have a lot of old projects that do this though, so here's my method
Public Function Relatorio()
Dim sql As String
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim rel As String
Set cn = New ADODB.Connection
cn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & enderecoDB & ";Jet OLEDB:Database"
cn.Open
Set rs = New ADODB.Recordset
dim path_To_XLSX
dim name_of_sheet
path_To_XLSX = "c:\temp\output.xlsx"
name_of_sheet = "Planilha1"
sql = sql = "SELECT * INTO [Excel 12.0;Database=" & path_To_XLSX & "]." & name_of_sheet & " FROM controle WHERE BP = '" & controlectform.nmbpbox.Value & "';"
rs.Open sql, cn
'If this application is in an unsecure environment, use the following code instead! This is to prevent a SQL injection, security concern here.
'As it is an Access Database, this is likely overkill for this project
'Create Command Object.
Set Cmd1 = New ADODB.Command
Cmd1.ActiveConnection = cn
cmd1.CommandText = "SELECT * FROM controle INTO [Excel 12.0;Database=" & path_To_XLSX & "]." & name_of_sheet & " WHERE BP = ?"
' Create Parameter Object.
Set Param1 = Cmd1.CreateParameter(, adInteger, adParamInput, 5) 'use adVarchar for strings(versus adInteger), https://www.w3schools.com/asp/met_comm_createparameter.asp
Param1.Value = controlectform.nmbpbox.Value
Cmd1.Parameters.Append Param1
Set Param1 = Nothing
Set Rs = Cmd1.Execute()
End Function
I had this challenge so many years ago that I cant remember but this link ring the bell. check if it help.
https://stackoverflow.com/a/28889774/382588
try { connw.Open(); OleDbCommand command; command = new OleDbCommand( "Update Deliveries " + "SET Deliveries.EmployeeID = ?, Deliveries.FIN = ?, Deliveries.TodaysOrders = ? , connw); command.Parameters.Add(new OleDbParameter("#EMPID", Convert.ToDecimal(empsplitIt[1]))); command.Parameters.Add(new OleDbParameter("#FIN", truckSplit[1].ToString())); command.Parameters.Add(new OleDbParameter("#TodaysOrder", "R")); catchReturnedRows = command.ExecuteNonQuery();//Commit connw.Close(); } catch (OleDbException exception) { MessageBox.Show(exception.Message, "OleDb Exception"); }
you can use this, to print the actual SQL.
Private Sub Command2_Click()
Dim db As Database
Dim qr As QueryDef
Set db = CurrentDb
For Each qr In db.QueryDefs
TextOut (qr.Name)
TextOut (qr.SQL)
TextOut (String(100, "-"))
Next
End Sub
Public Sub TextOut(OutputString As String)
Dim fh As Long
fh = FreeFile
Open "C:\Users\rs17746\Desktop\Text_Files\sample.txt" For Append As fh
Print #fh, OutputString
Close fh
End Sub
Here is one more version for you. This will export the results of each query, each to a separate text file.
Private Sub Command0_Click()
Dim qdf As QueryDef
Dim strFileName As String
For Each qdf In CurrentDb.QueryDefs
If Left(qdf.Name, 1) <> "~" Then
'you need to figure out TransferText command. Maybe
'you won't be lazy and expect people to read it to
'you and tutor you on how it works.
strFileName = qdf.Name
'Docmd.TransferText ....
DoCmd.TransferText transferType:=acExportDelim, TableName:=strFileName, FileName:="C:\test\" & strFileName & ".txt", hasfieldnames:=True
End If
Next qdf
MsgBox "Done"
End Sub

How to update Sql table from excel directly?

I have an sql database and I am able to connect with excel spreadsheet. But when I update the table from excel directly it's not updating the database and once I click refresh all the entered data is no longer in the excel table
Is it possible to update sql database from excel without using any queries?
There are many ways to do this. I'd recommend something like this, to push data from Excel to SQL Server.
Sub ButtonClick()
'TRUSTED CONNECTION
On Error GoTo errH
Dim con As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim strPath As String
Dim intImportRow As Integer
Dim strFirstName, strLastName As String
Dim server, username, password, table, database As String
With Sheets("Sheet1")
server = .TextBox1.Text
table = .TextBox4.Text
database = .TextBox5.Text
If con.State <> 1 Then
con.Open "Provider=SQLOLEDB;Data Source=" & server & ";Initial Catalog=" & database & ";Integrated Security=SSPI;"
'con.Open
End If
'this is the TRUSTED connection string
Set rs.ActiveConnection = con
'delete all records first if checkbox checked
If .CheckBox1 Then
con.Execute "delete from tbl_demo"
End If
'set first row with records to import
'you could also just loop thru a range if you want.
intImportRow = 10
Do Until .Cells(intImportRow, 1) = ""
strFirstName = .Cells(intImportRow, 1)
strLastName = .Cells(intImportRow, 2)
'insert row into database
con.Execute "insert into tbl_demo (firstname, lastname) values ('" & strFirstName & "', '" & strLastName & "')"
intImportRow = intImportRow + 1
Loop
MsgBox "Done importing", vbInformation
con.Close
Set con = Nothing
End With
Exit Sub
errH:
MsgBox Err.Description
End Sub
You can also try this, which uses a Where Clause.
Sub InsertInto()
'Declare some variables
Dim cnn As adodb.Connection
Dim cmd As adodb.Command
Dim strSQL As String
'Create a new Connection object
Set cnn = New adodb.Connection
'Set the connection string
cnn.ConnectionString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=True;Initial Catalog=Northwind;Data Source=Excel-PC\SQLEXPRESS"
'cnn.ConnectionString = "DRIVER=SQL Server;SERVER=Excel-PC\SQLEXPRESS;DATABASE=Northwind;Trusted_Connection=Yes"
'Create a new Command object
Set cmd = New adodb.Command
'Open the Connection to the database
cnn.Open
'Associate the command with the connection
cmd.ActiveConnection = cnn
'Tell the Command we are giving it a bit of SQL to run, not a stored procedure
cmd.CommandType = adCmdText
'Create the SQL
strSQL = "UPDATE TBL SET JOIN_DT = '2013-01-22' WHERE EMPID = 2"
'Pass the SQL to the Command object
cmd.CommandText = strSQL
'Execute the bit of SQL to update the database
cmd.Execute
'Close the connection again
cnn.Close
'Remove the objects
Set cmd = Nothing
Set cnn = Nothing
End Sub
Yes, you can directly via VBA or with other tools.
via VBA (via qry)
via SSIS (https://www.simple-talk.com/sql/ssis/moving-data-from-excel-to-sql-server-10-steps-to-follow/)
via managament studio (https://www.mssqltips.com/sqlservertutorial/203/simple-way-to-import-data-into-sql-server/)
via MS ACCESS (with ODBC connection to server)
...

Calling a macro from Excel ribbon control - VBA

So, I have a macro, LoadData, that I want to call in two separate macros, TransmitNewAndOldRecords and refresh, which are in turn called from a button on a custom tab of the Excel ribbon.
The TransmitNewAndOldRecords works fine. Here is the code for it. You can see the call at the second to last line of the macro.
Sub TransmitNewAndOldRecords(control As IRibbonControl)
'Reference Microsoft ActiveX Data Objects 6.1 Library
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim pgconn As String
Dim Year As String
Dim SQLDelete As String
Dim SQLInsert As String
Set conn = New ADODB.Connection
Set cmd = New ADODB.Command
Year = ActiveWorkbook.Sheets("SQL Creator").Range("Year").Value
pgconn = "Driver={PostgreSQL};" & _
"Server = me;" & _
"Port = 1234;" & _
"Database = database;" & _
"Uid = me;" & _
"Pwd = me;"
conn.ConnectionString = pgconn
conn.Open "PostgreSQL35W", "me", "me"
cmd.CommandType = adCmdText
cmd.ActiveConnection = conn
'Tests if there are any records to delete. If so, define SQLDelete variable and execute SQL string that is assigned to SQLDelete variable.
If WorksheetFunction.CountIf(Range("DELETE"), "Y") <> 0 Then
SQLDelete = DeleteRecords(ActiveWorkbook.Sheets("Budget").Range("DELETE"), Year)
cmd.CommandText = SQLDelete
cmd.Execute
End If
'Tests if there are any records to insert. If so, define SQLInsert variable and execute SQL string that is assgined to SQLInsert variable.
If WorksheetFunction.CountIf(Range("INSERT"), "Y") <> 0 Then
SQLInsert = InsertRecords(ActiveWorkbook.Sheets("Budget").Range("INSERT"), Year)
cmd.CommandText = SQLInsert
cmd.Execute
End If
conn.Close
'If there are no new/old records to insert/delete, then display message box stating that. IOF
If WorksheetFunction.CountIf(Range("DELETE"), "Y") = 0 And WorksheetFunction.CountIf(Range("INSERT"), "Y") = 0 Then
MsgBox "No data to insert/delete into/from table.", vbOKOnly
Else
MsgBox "Data saved successfully!", vbOKOnly
End If
Set conn = Nothing
Set cmd = Nothing
Call LoadData
End Sub
I also call the LoadData macro in a very simple macro, refresh (seen below), that just calls LoadData. I get an error (Wrong number of arguments or invalid property assignment) when I run refresh. However, if I add the "control as iRibbonControl" parameter to LoadData, it works just fine when called from refresh, but then I get an "Argument not optional" error in the TransmitNewAndOldRecords macro above when calling LoadData.
Sub refresh(control As IRibbonControl)
Call LoadData
End Sub
I'm really confused, because if I add the "control as IRibbonControl" parameter to LoadData, then the refresh macro works, but the TransmitNewAndOldRecords macro errors out. But, if I don't add the "control as IRibbonControl" parameter to LoadData, then the refresh macro errors out and the TransmitNewAndOldRecords works.
Does anybody know why this is happening?
Here is the LoadData macro in case it's needed:
Sub LoadData()
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim pgconn As String
Dim Team As Range
Dim FC As Range
Dim SQL As String
Set conn = New ADODB.Connection
Set rs = New ADODB.Recordset
Set cmd = New ADODB.Command
Set Team = ActiveWorkbook.Sheets("Info").Range("Info_Team")
Set FC = ActiveWorkbook.Sheets("Info").Range("Info_FundingCategory")
SQL = ActiveWorkbook.Sheets("SQL Creator").Range("BudgetSQL")
pgconn = "Driver={PostgreSQL};" & _
"Server = me;" & _
"Port = 1234;" & _
"Database = database;" & _
"Uid = me;" & _
"Pwd = me;"
conn.ConnectionString = pgconn
conn.Open "PostgreSQL35W", "me", "me"
cmd.CommandType = adCmdText
cmd.ActiveConnection = conn
cmd.CommandText = SQL
rs.Open cmd
ActiveWorkbook.Sheets("Budget").Range("A11:Y500").ClearContents
ActiveWorkbook.Sheets("Budget").Range("A11").CopyFromRecordset rs
rs.Close
conn.Close
End Sub