March 2, 2006 at 11:28 am
Greets.
This may or not be a good forum group to start in, if not, apologies.
Microsoft had no solution for this:
I have an Excel File, a Access Query, and a SQL Based Database. The
relation? The Access Query has both native and polled/linked tables to the
SQL native backend. A Query is designed in Access (for ease) to poll the SQL
side through the linked tables, and a couple of other crosstab queries. This
Access Query needs to be accessed from Excel Pivot Table Manager as a link to
an outside source.
The solution... a user can refresh their pivot table using ONLY Excel
collecting data from both Access AND SQL.
The method... use a Excel Pivot Table Manager.
The problem... "ODBC connection failed" to the SQL backend.
Hypothesis... Excel cannot pull third source data through the Access layer.
ODBC Connections have been verified that they exist and function for both
Access and the SQL side on the PC attempting this feat.
Environment: Dozens of queries have been designed in access as a primary
mode of data extraction from the SQL side. In fact, the primary interface to
the data is actually programmed through VB in Access. (Not my fault). The
problem is that we have layers of experienced users, primarily the ones
responsible for queries are only capable of designing them through Access.
The final End User for the Pivot tables is not allowed access to the queries,
for stability concerns, and lack of End Users experience in anything
complicated.
It is vital that the interaction for the End User is near zero to obtain the
data, and I have to work with the query writing person to pull things into
access.
Microsoft support has not been able to either fully understand or workaround
this issue.
Please e-mail me/ respond if you have additional questions for resolving
this. I am prepared to offer a graphic representation of this if necessary.
March 3, 2006 at 12:05 am
Try saving most of the Access queries in MSQuery queries...
The Excel users might also need to have the exact same ODBC dsn's defined on their computers as the people who created the queries on the ODBC linked SQL Server tables in Access in the first place.
Most of Access SQL's syntax can also be used directly in the MS-Query applet that Excel can fire up...but MS Query isn't installed by default anymore. Once you get it installed, copy the SQL for each Access query you want to use into the MSQuery's SQL space, connecting to the same ODBC datasource that was used to link the tables with in Access.
Or, save the queries in SQL Server views instead. Again, most of Access' SQL syntax is usable in SQL Server 7/2000/2005 straight up (Access pivot queries are not, nore are VBA functions, though, but SS2005 has a similar way to do it. WITH CUBE could also be helpful, esp. for pivot table source queries).
March 3, 2006 at 6:42 am
If you're using the "wizard" for Excel connectivity this is exactly what is happening, I'm afraid it hardwires the data source of the machine you're using.
Also, I really couldn't agree with corey more on this one, why are you using Access? Why introduce a flaky piece of dross into your solution when there's absolutely no need to do this? Yes, you can use queries built in Access Query builder and (pretty much, usually) cut and paste them directly into SQL, but from experience query builder puts a huge amount of rubbish into them anyway. Use stored procedures. If you're really not comfortable with coding them by hand then there is quite a good query builder in SQL 2000 itself......
Here's the solution we use for setting up data sources to Excel, it isn't perfect 'cos you have to hardwire the password into the app, but as long as you use a relatively harmless password (i.e. one that can only access and execute stored procedures) then you should be fine.....
This lot needs attaching to a form - I'll send you the actual spreadsheet if you want it, just send your email address in a private message.
Public Enum LTServers
LaserTracker = 1
End Enum
Public Enum DatabaseType
SQL_Server = 0
Oracle = 1
End Enum
Dim SvrType, DbName, SvrName, Uid, Pass As String
Dim jo() As String
Function Get_Connection_String(DB As DatabaseType, svr As String, Uid As String, pwd As String, DbName As String) As String
Dim Server As String
Dim DataBase As String
Dim CS As String
Select Case DB
Case 0 ' SQL SERVER
CS = "driver={SQL Server};server=" & svr & ";uid=" & Uid & ";pwd=" & pwd & ";database=" & DbName
'CS = "DSN=SQLServer;UID=sa;PWD=;"
Case 1 ' ORACLE
CS = "Provider=MSDASQL;driver={Microsoft ODBC for Oracle};server=" & DbName & ";uid=" & Uid & ";pwd=" & pwd & ";"
End Select
Get_Connection_String = CS
End Function
Sub ClearWorksheet(ByRef ws As Worksheet)
ws.UsedRange.ClearContents
End Sub
Public Function ParseDataSource(DS As String)
Dim j As Integer
jo = Split(DS, ";")
'j = InStr(1, jo(0), "=", vbTextCompare)
jo(0) = Mid(jo(0), InStr(1, jo(0), "=", vbTextCompare) + 1, Len(jo(0))) '
jo(1) = Mid(jo(1), InStr(1, jo(1), "=", vbTextCompare) + 1, Len(jo(1))) '
jo(2) = Mid(jo(2), InStr(1, jo(2), "=", vbTextCompare) + 1, Len(jo(2))) 'DatabaseName
jo(3) = Mid(jo(3), InStr(1, jo(3), "=", vbTextCompare) + 1, Len(jo(3))) 'DatabaseName
jo(4) = Mid(jo(4), InStr(1, jo(4), "=", vbTextCompare) + 1, Len(jo(4))) 'DatabaseName
'MsgBox jo(0)
'MsgBox jo(1)
'MsgBox jo(2)
'MsgBox jo(3)
'MsgBox jo(4)
End Function
Sub Get_DataSourceList()
Dim dbType As String
Dim xlsheet As Worksheet
Set xlsheet = Worksheets("setup")
frmSetup.cboDataSource.Clear
'Set cmd = Get_Command("Select * from DataSources")
'cmd.Open "driver={SQL Server};server=TUKDB002;uid=sa;pwd=sa;database=LaserTracker"
'Set rs = cmd.Execute("Select * from DataSources")
For i = 3 To 200
If Len(xlsheet.Cells(i, 1).Value) > 1 And Not xlsheet.Cells(i, 1).Value = "END" Then
ParseDataSource xlsheet.Cells(i, 1).Value
If jo(0) = "{SQL Server}" Then
jo(0) = "SQL_Server"
With frmSetup.cboDataSource
.AddItem jo(0) & " - " & jo(1) & " - " & jo(2) & " - " & jo(3) & " "
.List(.ListCount - 1, 1) = jo(0) 'DB Type
.List(.ListCount - 1, 2) = jo(1) 'ServerName
.List(.ListCount - 1, 3) = jo(4) 'Database Name
.List(.ListCount - 1, 4) = jo(2) 'userid
.List(.ListCount - 1, 5) = jo(3) 'password
End With
Else
jo(0) = "Oracle"
With frmSetup.cboDataSource
.AddItem jo(0) & " - " & jo(1) & " - " & jo(2) & " - " & jo(3) & " "
.List(.ListCount - 1, 1) = jo(0) 'DB Type
.List(.ListCount - 1, 2) = "" 'jo(2) 'ServerName
.List(.ListCount - 1, 3) = jo(2) 'Database Name
.List(.ListCount - 1, 4) = jo(3) 'userid
.List(.ListCount - 1, 5) = jo(4) 'password
End With
End If
End If
'frmSetup.cboDataSource.AddItem rs(0).Value
Next
End Sub
Sub Get_ProcedureList()
On Error GoTo 1
Dim cmd As New ADODB.Connection
Dim rs As New ADODB.Recordset
If Not frmSetup.cboDataSource.ListIndex >= 0 Then Exit Sub
frmSetup.cmbProcList.Clear
Select Case frmSetup.cboDataSource.List(frmSetup.cboDataSource.ListIndex, 1)
Case "SQL_Server" ' SQL Server
cmd.Open Get_Connection_String(frmSetup.cboServerType.ListIndex, frmSetup.txtServerName.Text, frmSetup.txtUserID.Text, frmSetup.txtPassword.Text, frmSetup.txtDatabaseName.Text)
Set rs = cmd.Execute("SELECT o.name FROM dbo.sysobjects o where (OBJECTPROPERTY(o.id, N'IsProcedure') = 1 or OBJECTPROPERTY(o.id, N'IsExtendedProc') = 1 or OBJECTPROPERTY(o.id, N'IsReplProc') = 1) and o.name not like N'#%%' and OBJECTPROPERTY(o.id, N'IsMSShipped') = 0 order by o.name")
Do While Not rs.EOF
frmSetup.cmbProcList.AddItem rs(0)
rs.MoveNext
Loop
rs.Close
cmd.Close
Case "Oracle" ' Oracle
cmd.Open Get_Connection_String(frmSetup.cboServerType.ListIndex, frmSetup.txtServerName.Text, frmSetup.txtUserID.Text, frmSetup.txtPassword.Text, frmSetup.txtDatabaseName.Text)
Set rs = cmd.Execute("Select Owner, View_Name from ALL_VIEWS WHERE OWNER = 'TLS' ")
Do While Not rs.EOF
frmSetup.cmbProcList.AddItem rs(0) & "." & rs(1)
rs.MoveNext
Loop
rs.Close
cmd.Close
Case Else
MsgBox frmSetup.cboDataSource.List(frmSetup.cboDataSource.ListIndex, 1)
End Select
Exit Sub
1
MsgBox Err.Description
End Sub
'*********** Procedures For Connecting TO a database *******
Function Get_Connection() As ADODB.Connection
Dim Cn As New ADODB.Connection
Dim CS As String
'''On Error Resume Next
CS = Get_Connection_String(frmSetup.cboServerType.ListIndex, frmSetup.txtServerName.Text, frmSetup.txtUserID.Text, frmSetup.txtPassword.Text, frmSetup.txtDatabaseName.Text)
Cn.ConnectionTimeout = 5
If CS = "OFFLINE" Then
Cn.Close
Else
Cn.Open CS
''Msgbox CN.State
End If
Set Get_Connection = Cn
End Function
Function Get_Connection2() As ADODB.Connection
Dim Cn As New ADODB.Connection
Dim CS As String
Dim xlsheet2 As Worksheet
Set xlsheet2 = Worksheets("Setup")
CS = xlsheet2.Cells(1, 1).Value
Cn.ConnectionTimeout = 5
If CS = "OFFLINE" Then
Cn.Close
Else
Cn.Open CS
''Msgbox CN.State
End If
Set Get_Connection2 = Cn
End Function
Function Get_Command2(SP As String) As ADODB.Command
Dim Cn As ADODB.Connection
Dim cmd As New ADODB.Command
'''On Error Resume Next
cmd.ActiveConnection = Get_Connection2()
cmd.CommandText = SP
cmd.CommandType = adCmdStoredProc
Set Get_Command2 = cmd
End Function
Function Get_Command(SP As String) As ADODB.Command
Dim Cn As ADODB.Connection
Dim cmd As New ADODB.Command
'''On Error Resume Next
cmd.ActiveConnection = Get_Connection()
cmd.CommandText = SP
cmd.CommandType = adCmdStoredProc
Set Get_Command = cmd
End Function
'******************************************************************************
Function Get_Record_Set(SP As String) As ADODB.Recordset
Dim cmd As New ADODB.Command
On Error Resume Next
Set cmd = Get_Command(SP)
Set Get_Record_Set = cmd.Execute()
End Function
'******************************************************************************
'***STORED PROCEDURES**********************************************************
--This is where you define the stored procedures you want to call
Function sp_lm_laser_planning_PO_Status(Server As LTServers, PO_NO As Integer) As Integer
Dim cmd As New ADODB.Command
Dim rs As New ADODB.Recordset
Dim prm1 As ADODB.Parameter
Dim ret_val As Integer
On Error Resume Next
Set cmd = Get_Command(Server, "sp_lm_laser_planning_PO_Status")
Set prm1 = cmd.CreateParameter("Production Order No", adInteger, adParamInput, , PO_NO)
cmd.Parameters.Append prm1
Set rs = cmd.Execute
If rs.State = 1 Then
ret_val = rs(0).Value
rs.Close
Else
ret_val = 0
End If
cmd.ActiveConnection.Close
sp_lm_laser_planning_PO_Status = ret_val
End Function
Function lm_sp_laser_planning_get_item_name(Server As LTServers, Item_code As String) As String
Dim cmd As New ADODB.Command
Dim rs As New ADODB.Recordset
Dim prm1 As ADODB.Parameter
Dim ret_val As String
On Error Resume Next
Set cmd = Get_Command(Server, "lm_sp_laser_planning_get_item_name")
Set prm1 = cmd.CreateParameter("Item Code", adChar, adParamInput, 10, Item_code)
cmd.Parameters.Append prm1
Set rs = cmd.Execute
If rs.State = 1 Then
ret_val = rs(1).Value
rs.Close
Else
ret_val = ""
End If
cmd.ActiveConnection.Close
lm_sp_laser_planning_get_item_name = Trim(ret_val)
End Function
Function lm_sp_laser_planning(Server As LTServers) As ADODB.Recordset
Dim rs As New ADODB.Recordset
'On Error Resume Next
Set rs = Get_Record_Set(Server, "lm_sp_laser_planning")
Set lm_sp_laser_planning = rs
End Function
Function sp_lm_get_item_list(Server As LTServers) As ADODB.Recordset
Dim rs As New ADODB.Recordset
Set rs = Get_Record_Set(Server, "sp_lm_get_item_list")
Set sp_lm_get_item_list = rs
End Function
March 3, 2006 at 10:12 am
I already responded to Richard directly, and here is a portion of my response.
Corey, I think you might be closer to the solution. I will attempt to recreate the SQL statements directly into MS-Query. I don't think I have tried that completely yet.
If this works though, I think I may have a more interested challenge in automating the conversion from the SQL generated code in Access (which b.t.w. I agree with Richard on the overhead, but hey, if it works consistently....) to MS-Query, whenever the Access Query programmer decides he wants a different lookup criteria.
Please feel for me here folks.... I would definitely prefer to do this *ALL* in SQL, since that is the native format of the backend data, but alas, shifting paradigms and teaching people SQL is a much bigger immediate challenge.
Response to Richard as Follows:
You see, the Pivot table is connected to an external connection throught the ODBC driver for Access database objects.
The Access Database object has a crosstab query that I need to have excel pivot.
In the Access Database, the query calls other sub-queries, that are tied with linked tables.
The linked tables are linked to the SQL backend.
I can access the Access queries that are only dealing with non-externally linked table (i.e. Access native tables) -OR- directly to the SQL tables and queries.
I believe what I really need is a ODBC driver that can -chain- multiple connections with thier proper authentications.
For my personal level of programming, I can poll datasources based on programmatical sql statements, but the queries are already made and maintained throught the Access query editor.
Coding a solution would be great if there were only one or two queries I had to replicate in .NET language (specifically VB.NET), but there are many, so I need to work with the applications themselves, and also make it easy for non-programmers to continue to design queries in Access.
March 8, 2006 at 4:22 pm
Okay, this didn't work out right. Here's why:
This is the "Master" Select Statement that I need to run in the Query editor, Most of this accesses the SQL backend:
SELECT tblInItem.ItemId, tblInItem.Descr, tblInItemAddlDescr.AddlDescr, [IN - On Hand Qty].onhand
FROM (tblInItem LEFT JOIN tblInItemAddlDescr ON tblInItem.ItemId = tblInItemAddlDescr.ItemId) LEFT JOIN [IN - On Hand Qty] ON tblInItem.ItemId = [IN - On Hand Qty].ItemId
WHERE (((tblInItem.ItemStatus)=1) AND ((tblInItem.SalesCat)="PR") AND ((tblInItem.UsrFld1)="yes"))
ORDER BY tblInItem.ItemId;
Notice that the " [IN - On Hand Qty].onhand " is actually a reference to another query in ACCESS:
SELECT Sum([qty]-[invoicedqty]-[removeqty]) AS onhand, tblInQtyOnHand.ItemId
FROM tblInQtyOnHand
GROUP BY tblInQtyOnHand.ItemId
Two issues exist here. First, since I am loading the ODBC driver for the SQL backend, the [IN - On Hand Qty].onhand is fouling up due to the fact it in is an ACCESS table.
Secondly, although I could theoretically combine the two, (I am not quite sure yet how to nest select statements) I would have to do this for ALL the items I am importing into Excel, some of which have SEVERAL ties to Access tables that I would have to nest into the main SQL statement.
Sure it is job security that I would become a doggon expert at writing nested SQL statements, and I wouldn't mind doing it if I didn't have a network to run as well, there HAS to be another alternative like a nested odbc connection that can take tables from two completely different sources.
Please help obi-wan, you're our only hope!!!
March 8, 2006 at 4:51 pm
I've lost the thread of this topic and only read your most recent post....
You could, although it's probably ugly, have SQL Server have a linked server back to your Access DB. Then you could write the entire query in SQL Server's universe which can access the Access DB via the linked server mechanism... I'm not sure if this fits in with the rest of your post regarding Excel + Access + SQL - there's surely got to be a smoother way of doing things....... Good luck!
March 8, 2006 at 5:01 pm
I thought of that as well Ian. Thanks for that though. The problem on that is that the owner of the queries is only familiar with Access, and is an Accessite (new word for Access Fanatic)
For this moment, I am wondering if someone could give me a quick example of nesting select statements in SQL until we can figure this out a better way through Excel + Access + SQL .
March 8, 2006 at 8:19 pm
Tobias,
Rewriting your query as a nested one would look like this:
SELECT tblInItem.ItemId, tblInItem.Descr, tblInItemAddlDescr.AddlDescr, [IN - On Hand Qty].onhand
FROM (tblInItem LEFT JOIN tblInItemAddlDescr ON tblInItem.ItemId = tblInItemAddlDescr.ItemId)
LEFT JOIN
(SELECT Sum([qty]-[invoicedqty]-[removeqty]) AS onhand, tblInQtyOnHand.ItemId
FROM tblInQtyOnHand
GROUP BY tblInQtyOnHand.ItemId) as [IN - On Hand Qty]
ON tblInItem.ItemId = [IN - On Hand Qty].ItemId
WHERE (((tblInItem.ItemStatus)=1) AND ((tblInItem.SalesCat)="PR") AND ((tblInItem.UsrFld1)="yes"))
ORDER BY tblInItem.ItemId;
The subquery is enclosed in brackets as part of the From clause and given a name that it can be referred to by in other clauses of the select query.
I have done a little bit of playing around with getting Access to "pass on" ODBC linked tables and had little joy. I did not do any extensive testing or searching, but what I did try was not pretty.
Viewing 8 posts - 1 through 7 (of 7 total)
You must be logged in to reply to this topic. Login to reply