I can successfully create a pivot table in excel vba 2010 with the following code where the data come from an MS access database,
Dim con As New ADODB.Connection
Dim rs As New ADODB.Recordset
con.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=H:\SQL.accdb"
rs.Open "SELECT * FROM Table1", con, adOpenStatic, adLockReadOnly
Set piv = ActiveWorkbook.PivotCaches.Create(xlExternal)
Set piv.Recordset = rs
piv.CreatePivotTable TableDestination:=Range("A1"), TableName:="P2"
con.Close
Set rs = Nothing
Set con = Nothing
But i when i change the SQL code of the recordset then the pivot can't be refreshed. In fact the pivot table has to be deleted and created over. Is there a way i can create a pivot table this way and refresh the data without deleting the pivot table.
The above answer was not quite what i was look for as different users would query from the database and will be using parameters as well, which could cause problems when multiple users query at the same time. But i did found a way to around my problem.
The code i placed above in my question, I can use to initially create my pivot and pull all the data through. I then build a separate Sub that can refresh the pivot table that looks as follows,
Dim con As New ADODB.Connection
Dim rs As New ADODB.Recordset
con.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=H:\SQL.accdb"
rs.Open "SELECT * FROM Table1", con, adOpenStatic, adLockReadOnly
With Sheets(1).PivotTables("P2").PivotCache
Set .Recordset = rs
.Refresh
End With
Set rs = Nothing
con.Close
Set con = Nothing
A quick-fix, depending on how you usually update the SQL code, is as follows.
In ACCESS , create a query, using SQL mode as
SELECT * FROM Table1 and save it as Query1
In EXCEL, modify your code to SELECT * FROM Query1
That way, Excel will treat Query1 as a Table for all practical purposes and you may make Query1 in Access as complicated as you'd like, Excel will still pull up all its contents, keeping your code reusable.
Related
I'm using an MS Access Database 2013 as frontend to connect to a MS SQL Server 2017.
Dim rst As New ADODB.Recordset
Dim cmd As New ADODB.Command
Dim conn As New ADODB.Connection
With conn
.CursorLocation = adUseClient
.ConnectionString = strSQLOLEDB
.Open
End With
cmd.CommandType = adCmdStoredProc
cmd.CommandText = strStoredProcedure
cmd.ActiveConnection = conn
cmd.CommandTimeout = 120
cmd.Parameters.Append cmd.CreateParameter(strID_Bez, adInteger, adParamInput, , intID)
rst.Open cmd, , adOpenKeyset, adLockOptimistic
This worked fine for me and I also could use an Trigger to set the changing date/time as a manual timestamp:
CREATE TRIGGER [dbo].[tr_Emailadress_After_Update]
ON [dbo].[Emailadress] AFTER Update, Insert
AS
BEGIN
SET NOCOUNT ON;
UPDATE Emailadress
SET Email_TS = sysdatetime()
WHERE Email_ID IN ( SELECT Email_ID
FROM inserted
)
Now I'm trying to use the OLTP In-Memory-Technic of MS SQL Server (that's also the reason for the manual timestamp as OLTP does not offer a timestamp) and the Trigger does not work any more.
I searched a lot for a solution and found out, that this will work for me:
CREATE TRIGGER [dbo].[tr_Emailadress_After_Update] ON [dbo].[Emailadress] WITH NATIVE_COMPILATION, SCHEMABINDING AFTER Update , INSERT
AS
BEGIN ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'german')
DECLARE #intEmail_ID int
SELECT #intEmail_ID = I.Email_ID
FROM Inserted I
UPDATE dbo.Emailadress
SET Email_TS = sysdatetime()
WHERE Email_ID = #intEmail_ID
END
GO
But now I'm having another problem. I can change data in my Access form, but because of the Trigger the change will not be committed. Without Trigger it works fine... but with Trigger not. If I'm sending an Update directly at SSMS to the table trigger & change will work fine. If I delete the trigger Access will work fine.
I tried to change the TRANSACTION ISOLATION LEVEL but did not found a solution for the problem.
I have a recordset and I want to copy this in new table in sql using VB Script. new table should be created as per recordset only. Someone has examples?
I know how to create new table but how to copy entire recordset to this table. I have something like following code and my recordset is retrieved in oRs variable.
Set oRs = CreateObject("ADODB.Recordset")
Set oCom = CreateObject("ADODB.Command")
oCom.CommandText = "my command text"
Set oRs = oCom.Execute
Kbv.
I'm writing some Excel VBA for a user to be able to insert records into a SQL Server table, using ADODB. This is working fine:
Dim conn As New ADODB.connection
conn.Open "<my connection string>"
Dim records As New ADODB.Recordset
records.CursorLocation = adUseClient
records.Open "SELECT TOP 1 * FROM [MyTable]", conn, adOpenStatic, adLockBatchOptimistic, adCmdText
' (Add some stuff here.)
records.UpdateBatch
Something's nagging me, though: is it possible to get the recordset pointed at the right table without doing a SELECT up front? This could get to be a pretty big table, so SELECT * FROM [MyTable] is out. I'm limiting that with a TOP 1, but I'm only doing a write, so it feels like I shouldn't have to do that!
The documentation makes it sound like you can just put a table name in the Source argument:
Use the optional Source argument to specify a data source using one of the following: a Command object variable, an SQL statement, a stored procedure, a table name, [...]
In practice, this doesn't work for me, and all of the following just error out with the message below, like it thinks I'm calling a stored procedure:
records.Open "MyTable", conn, ' [...]
records.Open "[MyTable]", conn, ' [...]
records.Open "[dbo].[MyTable]", conn, ' [...]
The request for procedure 'MyTable' failed because 'MyTable' is a table object.
Is there some syntax I'm missing here, or do I just have to go with the SELECT?
I have a table containing business priorities and the name of the query that is used to generate the results for each.
Is it possible to loop through this table and where it finds a query in the database with the same name, run it?
The closet thing I have found is below but I don't want to input my full query codes into a table.
http://www.experts-exchange.com/Database/MS_Access/Q_28284655.html
This will execute every query name that is in your table. It fills a recordset with the query names and then loops through and executes each one.
Dim sql As String
Dim rst As DAO.Recordset
Dim myQuery As String
sql = "Select myQuery from myTable"
Set rst = CurrentDb.OpenRecordset(sql)
Do While Not rst.BOF And rst.EOF
myQuery = rst(0)
DoCmd.OpenQuery myQuery, acViewNormal
rst.MoveNext
Loop
rst.Close
Set rst = Nothing
Let me know if you need to check to see if the query exists before you execute it. If so, I can add the code to search the querydefs collection for a query with the same name and only execute it if a match is found.
I'm using a bulkcopy to a temp table that then will be used to MERGE to the main table. All is working but when I try dropping my temp table, I get an error saying 'Table '#temptable' does not exist'
Basically I do the following.
'get data from excel to a datatable.
Dim cmd As New OleDbCommand(sqlstring, excelConnection)
dt.Load(cmd.ExecuteReader())
'create sql connection
Using sqlcon As SqlConnection =
New SqlConnection(ConfigurationManager.ConnectionStrings("SQLCON").ConnectionString)
sqlcon.Open()
'create temp table
Dim sqlcmd As New SqlCommand("create table #tbltemp (ID int, FirstName nvarchar(50),LastName nvarchar(50),JobDesc nvarchar(50))", sqlcon)
sqlcmd.ExecuteNonQuery()
Try
'start bulcopy
Using bulkcopy As SqlBulkCopy = New SqlBulkCopy(sqlcon)
'map columns
Dim mapID As New SqlBulkCopyColumnMapping("ID", "ID")
bulkcopy.ColumnMappings.Add(mapTMID)
Dim mapFName As New SqlBulkCopyColumnMapping("FirstName", "FirstName")
bulkcopy.ColumnMappings.Add(mapFName)
Dim mapLName As New SqlBulkCopyColumnMapping("LastName", "LastName")
bulkcopy.ColumnMappings.Add(mapLName)
End Using 'end bulkcopy using
'Inserts new records to main from temptable
Dim mergesql As String = "merge into dbo.Main as Target " & _
"using #tbltemp as Source " & _
"on " & _
"(Target.ID = Source.ID) " & _
"when not matched then " & _
"insert (ID,FirstName,LastName) values (Source.ID,Source.FirstName,Source.LastName);"
sqlcmd.CommandText = mergesql
sqlcmd.ExecuteNonQuery()
'Clean up stuff
cmd.CommandText = "DROP TABLE [#tbltemp]"
cmd.ExecuteNonQuery()
Catch ex As Exception
Response.Write(ex.Message)
Finally
'close sql con
sqlcon.Close()
End Try
'close excel con
excelConnection.Close()
End Using ' end using sqlcon
Like I said, everything seems to be working except for dropping the table. Does this means that temp table has been dropped automatically?
I tried running some tests and searched around but no luck.
cmd is the OleDbcommand associated with you excelconnection and not a SqlCommand associated with your Database connection.
Incidently, I use this technique all the time and you can also create the temporary table as...
Select Top 0 * Into #tbltemp From dbo.Main
This save on defining the columns in a static create table statement.
Also if you are working with temp tables a lot within the same connection then you can check it exists and drop it using...
If Object_Id('TempDB..#tbltemp') Is Not Null Drop Table #tbltemp
SQL Server will automatically drop temp tables when the connection closes, so there isn't actually any need for you to do this.
Not sure why it is failing on the drop part though. You might not have the right permissions.