William Benson (VBACreations.Com)
vbacreations at gmail.com
Thu Aug 4 23:04:50 CDT 2011
I just can't seem to finesse this, thought maybe someone else could think of a way. I wrote some code which examines a crosstab query and updates a couple more queries which are dependent on that one. I have to do this because the data which the crosstab pivots changes over time and all the queries that depend on the crosstab become obsolete. The code is a little cumbersome, but works. What I am looking for is some way to call that function's code prior to my current top level query, but do it from a new top level query. I think I will have to use a macro or VBA ... but I was wondering if there might just be some clever construction in a new top level query, that calls the function updating its dependent queries, and uses '*' to pull all records from the previous top level query ... without it having to know ahead of time what those columns were going to be. I tried this SELECT * FROM (SELECT * FROM OldTopLevelQuery) WHERE (((BuildAndRunEquipmentQueries())=True)); I thought great, since I am not listing any columns and since I have a WHERE clause that calls the function, I would be home free. But somehow Access still goes behind the scenes, creates a query plan with whatever it knew about OldTopLevelQuery at the time this query got built ... then if any of those columns disappear, the query fails. Even though it is just asking for '*'. Go figure. So is there something else that I can do? Here is the code, I don't think anyone needs to examine it to answer the above question Y/N. Please remove code in your replies to avoid message length limitations. Thanks! Function BuildAndRunEquipmentQueries() As Boolean Const CROSSTAB = "qry_4444_Part2_Crosstab" Const QUERYTOFIX1 = "qry_4444_Part3" Const QUERYTOFIX2 = "qry_4444_Final" Dim sFirstFields As String Dim sTempName As String Dim SQL As String Dim D As DAO.Database Dim R As DAO.Recordset Dim ArrFields() As String Dim Q As DAO.QueryDef Dim iLB As Long Dim iUB As Long Dim SQLTest As String Dim bFound As Boolean Dim i As Long, j As Long Dim sGrandTotal As String Dim sFields As String Set D = CurrentDb 'putting TempTextToBeSwapped as the table alias because we will change that to 'A' later, and 'we won't be able to check elements coming back from 'FieldListFromQuerySQL(CROSSTAB) 'If we leave the "tablename." in the field list ... thereore we give something unique 'so using Replace$ before testing the field won't screw up the field names sFirstFields = "" sFirstFields = sFirstFields & "," & "TempTextToBeSwapped.[GLOBAL_DB]" sFirstFields = sFirstFields & "," & "TempTextToBeSwapped.[Global_Customer_Name]" sFirstFields = sFirstFields & "," & "TempTextToBeSwapped.[Regional_DB]" sFirstFields = sFirstFields & "," & "TempTextToBeSwapped.[Regional_Customer_Name]" sFirstFields = sFirstFields & "," & "TempTextToBeSwapped.[SITE_DB]" sFirstFields = sFirstFields & "," & "TempTextToBeSwapped.[Site_Customer_Name]" sFirstFields = sFirstFields & "," & "TempTextToBeSwapped.[Site_Station_Name]" sFirstFields = Mid(sFirstFields, 2) ArrFields = FieldListFromQuerySQL(CROSSTAB) iUB = UBound(ArrFields) iLB = LBound(ArrFields) sFields = "" sGrandTotal = "" For i = iLB To iUB bFound = False If InStr(UCase(Replace(sFirstFields, "TempTextToBeSwapped.", "")), UCase(ArrFields(i))) = 0 Then sFields = sFields & "," & "A." & ArrFields(i) sGrandTotal = sGrandTotal & "+ NZ(" & "A." & ArrFields(i) & ",0)" End If Next sFirstFields = Replace$(sFirstFields, "TempTextToBeSwapped.", "A.") If sFields <> "" Then sFields = Trim(Mid(sFields, 2)) sGrandTotal = Trim(Mid(sGrandTotal, 2)) 'QUERYTOFIX1 SQL = "SELECT " SQL = SQL & sFirstFields & "," & sFields & "," SQL = SQL & sGrandTotal & " As Grand_Total" SQL = SQL & " FROM" SQL = SQL & " [" & CROSSTAB & "] as A" SQL = SQL & " ORDER BY " SQL = SQL & sGrandTotal & " DESC" SQLTest = "Select * from (" & SQL & ") WHERE 1 = 2" Set R = Nothing On Error Resume Next Set R = D.OpenRecordset(SQLTest) If Not R Is Nothing Then 'SQL will work Set Q = Nothing sTempName = "qry_temp_" & Format(Timer + 1, "00000000") Set Q = D.CreateQueryDef(sTempName, SQL) D.QueryDefs.Refresh If Not Q Is Nothing Then Set Q = Nothing Set Q = D.QueryDefs(QUERYTOFIX1) If Q Is Nothing Then Set Q = D.CreateQueryDef(QUERYTOFIX1, SQL) D.QueryDefs.Refresh Else Q.SQL = SQL End If Else MsgBox "Unable to modify the query " & QUERYTOFIX1 End If Else MsgBox "Unable to modify the query " & QUERYTOFIX1 End If 'QUERYTOFIX2 SQL = "SELECT " SQL = SQL & sFirstFields & "," & sFields & "," SQL = SQL & " A.Grand_Total" SQL = SQL & " FROM " SQL = SQL & " [qry_4444_Part3] as A" SQL = SQL & " INNER JOIN" SQL = SQL & " [qry_4444_Part4] as B" SQL = SQL & " ON" SQL = SQL & " A.GLOBAL_DB = B.GLOBAL_DB" SQL = SQL & " ORDER BY " SQL = SQL & " B.SumOfGrand_Total DESC, A.GLOBAL_DB, A.Grand_Total DESC" SQLTest = "Select * from (" & SQL & ") WHERE 1 = 2" Set R = Nothing On Error Resume Next Set R = D.OpenRecordset(SQLTest) If Not R Is Nothing Then 'SQL will work Set Q = Nothing sTempName = "qry_temp_" & Format(Timer + 2, "00000000") Set Q = D.CreateQueryDef(sTempName, SQL) D.QueryDefs.Refresh If Not Q Is Nothing Then Set Q = Nothing Set Q = D.QueryDefs(QUERYTOFIX2) If Q Is Nothing Then Set Q = D.CreateQueryDef(QUERYTOFIX2, SQL) D.QueryDefs.Refresh Else Q.SQL = SQL End If BuildAndRunEquipmentQueries = True Else MsgBox "Unable to modify the query " & QUERYTOFIX2 End If Else MsgBox "Unable to modify the query " & QUERYTOFIX2 End If Else MsgBox "Unable to properly test [" & CROSSTAB & "] nor update its successor queries." End If End Function Function FieldListFromQuerySQL(sQryName As String) As Variant Dim D As DAO.Database Dim R As DAO.Recordset Dim F As DAO.Field Dim Arr() As String Dim sList As String Set D = CurrentDb Set R = D.OpenRecordset("Select * from [" & sQryName & "] where 1 = 2") For Each F In R.Fields sList = sList & "|[" & F.Name & "]" Next If sList <> "" Then sList = Mid(sList, 2) Arr = Split(sList, "|") End If FieldListFromQuerySQL = Arr End Function