Alias a Caption in Access 2007 - ms-access

All right, I've got two tables in my Access 2007 database (well, more than that, but the question applies to these two...):
part
part_no
...
supplier_id
special_supplier_id
...
And
supplier
supplier_id
supplier_nm (NB: Caption="Supplier Name")
special_supplier_flg
Now I've built a query :
SELECT p.part_no, s.supplier_nm, ss.supplier_nm AS special_supplier_nm
FROM
part AS p INNER JOIN
supplier AS s ON p.supplier_id = s.supplier_id INNER JOIN
supplier AS ss on p.supplier_id = ss.supplier_id
All well and good, and it seems to work for the simple select (if there are any errors in the query itself, it's an artifact of retyping it for the question, and not what the question is about), and should work for code applications as well.
The problem, though, is that if I open the datasheet view of the query, both of the name fields are labeled "Supplier Name". Is there any way around this?

Try this:
SELECT p.part_no, s.supplier_nm, (ss.supplier_nm + '') AS special_supplier_nm. . .
However, if you're using the query builder you may need to be careful not to build the query with the "default" alias (from the caption) first, because that seems to stick around in some not-visible metadata.
Also, if you can edit this query in Access' query builder, if you right click on the field in question there is an option to set the caption property inside the query, and this will override whatever caption was on the original table column.

I see the same thing with Access 2003 for even a single-table query ... if the source field has a Caption assigned, that caption is used as the column header in the query datasheet view, regardless of whether or not I give the field an alias in the query definition.
Other than removing the Caption from the source table definition, the only way I could find to work around it was by manually re-assigning the field's Caption property with VBA. Query1 includes a field named id which has "Foo ID" as its Caption in the source table:
CurrentDb.QueryDefs("Query1").Fields("id").Properties("Caption") = "foo_id"
That command did cause the query datasheet view to use foo_id as the column header.
If you assign an alias to a query field, that alias is used as the name in the query's Fields collection. You can examine your query's field names and their captions with this procedure:
Public Sub InspectQueryFieldCaptions(ByVal pQuery As String)
Dim fld As DAO.Field
Dim strMsg As String
On Error GoTo ErrorHandler
For Each fld In CurrentDb.QueryDefs(pQuery).Fields
Debug.Print "Field: " & fld.Name, "Caption: " & fld.Properties("Caption")
Next fld
ExitHere:
Set fld = Nothing
On Error GoTo 0
Exit Sub
ErrorHandler:
Select Case Err.Number
Case 3270 ' Property not found. '
Debug.Print "Field: " & fld.Name, "no caption"
Resume Next
Case Else
strMsg = "Error " & Err.Number & " (" & Err.Description _
& ") in procedure InspectQueryFieldCaptions"
MsgBox strMsg
GoTo ExitHere
End Select
End Sub

Do you have captions set in your table definition? Those definitions will show instead of what you alias. Since you are selecting a column that will have the same caption (reguardless of alias), you will see the same caption for both in the datasheet view.
Do you have the option to change the caption field? Leaving it blank will use its given name (or alias in the event of a view)

WORKAROUND THAT WORKS
OK this one has been driving me bonkers because I'm using lots of data from linked (imported) tables from our company's finance, HR and CRM systems all set up by the same developer who thought captioning every Index "ID:" was a great idea. but when you have an aggregating which brings many of these together you get a big error prone mess because the subsequent query can't work out which "ID:" is which. He's my solution:
Rather than simply passing the values through, which simply passes the caption: If the field you want to re-caption is a value field, just re-label it and multiply it by 1 like so (in this my per_id field is captioned ID:):
Perid: 1*[pe_id]
This results in a new field labelled Perid
If it is a text field just concatenate it with nothing like this:
Perid: ""&[fname]
It works.

Related

Define table in select query from the value of a text box

I have a very basic select query in MS Access. The only variable is that I want the user to select the region from a drop down list (combo box). There is a different table for each region, so I want the FROM field to pull from the combo box.
My query looks like this:
SELECT
STOCK_CODE, STOCK DESCRIPTION
FROM
Forms![frm_MAIN_MENU]![txt_MAIN_MENU_REGION]
When I run this I get the following error:
"Syntax error in FROM field"
I think I have read somewhere that this is not possible? If someone can perhaps clarify?
Thank you
This is one example of why the database structure that you have setup is not a very good idea. Using this sort of design will mean that you have to work much harder to get the database to work properly.
A far better design would be to replace all of your individual tables with one table, and add a field in their that identifies the region. You will then be very easily able to filter this single table on this region identifier.
Having said that, if you really want to do it this way, it can be done in VBA. Assuming that [txt_MAIN_MENU_REGION] is your combo box, and is populated with your regions:
Private Sub txt_MAIN_MENU_REGION_AfterUpdate()
On Error GoTo E_Handle
Dim strSQL As String
If Not IsNull(Me!txt_MAIN_MENU_REGION) Then
strSQL = "SELECT STOCK_CODE, [STOCK DESCRIPTION] FROM " & Me!txt_MAIN_MENU_REGION
End If
Me!lstRegion.RowSource = strSQL
sExit:
On Error Resume Next
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "frmRegion!txt_MAIN_MENU_REGION_AfterUpdate", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume sExit
End Sub
Regards,

change a field's value with vba

I want to change a date in a specific table to today's date by clicking a button in a related form. So all the button does is changing the date in a certain field in my DB. Is there a simple way to do this with VBA?
*Update
Well I wrote this in my VBA code:
CurrentDb.Execute "UPDATE Machines SET LastMaintenance = Date() WHERE MachineID = MachineID.Value"
With "Machines" being my table, "LastMaintenance" the column containing the date that has to be changed into today's date, "MachineID" the name of the record and "MachineID.Value" the name of the textbox bound to that same record.
When I click the button I get this error:
"Not enough parameters. 1 expected."
When performing an update query, you'll want to be cognizant of the datatype for each field, as you will have to present it differently in your code. Also, you will need to break up your string text when inserting a variable. In your current state, it's looking for a MachineID field with 'MachineID.value' as its contents. Try this:
CurrentDb.Execute "UPDATE Machines SET LastMaintenance = Date() WHERE MachineID = " & MachineID.Value
The most straightforward way is to run a UPDATE query.
CurrentDB.Execute "UPDATE someTable SET someDate = Date() WHERE stuff = 47"
If
a button in a related form
means a form bound to that table displaying the record you wish to update, use the OnClick event of the button:
Private Sub NameOfYourButton_Click()
Me![NameOfYourDateField].Value = Date
' Optionally, save the record at once:
Me.Dirty = False
End Sub
An UPDATE command is dangerous because you are making a change to the database assuming sane inputs. I would recommend using parameterized VBA code to avoid both SQL injection and throw an error in VBA for malformed inputs.
This example uses a static string to load your recordset, then it clearly states that the unverified input is only used in a Find command. Then it only acts if a matching record is found. This is a safer operation, albeit more verbose. It's also debuggable in VBA where the SQL UPDATE command is a kind of black box.
With CurrentDb.OpenRecordset("Machines", dbOpenDynaset)
.FindFirst "[MachineID]=" & CLng(MachineID.Value)
If .NoMatch Then
Debug.Print "ID not found: " & MachineID.Value
Else
.Edit
.Fields.Item("LastMaintenance").Value = Date()
.Update
End If
.Close
End With

Wrong RecordCount on Filtered Form with SQL View DataSource

I am using an Access2010 project as frontend, referring to a MS SQL Server 2008 as backend. Within my Access project there is form frmKlientenÜbersicht. This form has a view abfKlientenÜbersicht as dataSource.
Now I am trying to get the current number of records showing up in my form by using this code:
Private Sub Form_Current()
Debug.Print "Form_Current: " & anzahlDatensätze
lblAnzahlDatensätze.Caption = anzahlDatensätze & " Klient(en)"
End Sub
Private Function anzahlDatensätze() As Integer
Dim rs As Recordset
Set rs = Me.RecordsetClone
rs.MoveLast
anzahlDatensätze = rs.RecordCount
End Function
This works fine until I am using some filters. If I am using any filter on my form, the number of records stays unchanged!
What do I have to change to get the current number of records showing up (if filtered or not)?
What is the reason why my code does not show the correct number of records?
EDIT: According to the given comments and answers I tried setting Count([pkKlient] onto a textbox (see new pic) and tried DCount("*", "abfKlientenÜbersicht", me.Filter) from within VBA Code.
Unfortunatelly it seems that the filterClause is not valid when using it as parameter value for DCount. (see pic for filterClause).
As you can see count(..) does not result in a correct number - and the filterClause (generated by access!!) seems not to be valid for use by DCount(..)
If someone wants to try it, on your own, just create an ADP, add a form, add a view, form dataSource is a view, set a filter, and try to get the number of records?!!
Looking forward for any comments/answers/hints!
with VBA, DCount will give you what you need
DCount("*", "MyTable", Me.Filter)
If you want to put this on the form, there's an easier way. use an unbound box, and set it to =count([FieldName])
This count should remain correct, regardless of if it's counted filtered records or not.
Some notes, there are a dozen things that could go wrong with this, it could hardly even be called tested. However, it was returning the correct count for me.
Apparently, the form filter just hides records, whereas this will apply a real filter. However, you need to get the format into the right shape for a valid filter. In the end, a WHERE statement would probably be easier.
Private Sub Form_ApplyFilter(Cancel As Integer, ApplyType As Integer)
With Me.Recordset
''Filter
If ApplyType = 1 Then
''Very, very roughly. Remove form name, use single quotes
''You will need a lot more code for safety
sfilter = Replace(Me.Filter, "[" & Me.Name & "].", "")
sfilter = Replace(sfilter, """", "'")
.Filter = sfilter
MsgBox "Recordset : " & Me.Recordset.RecordCount & vbCrLf _
& "Filtered : " & .RecordCount
Else
''Remove filter - ApplyType 0
.Filter = ""
End If
End With
End Sub
Additional note with similar caveats
You can also set a textbox to something on these lines:
=IIf([FilterOn]=True,DCount("id","ATable",
Replace(Replace([Filter],"[" & [Name] & "].",""),"""","'")),Count([id]))
(Remove the break in the line, it is cosmetic)

VBA Executing CODE from a ComboBox

I have a very complex process that involves downloading a number of files from different shares, concatenating those files into working tables, manipulating and calculating related information, and then exporting specific fields (and calculations) as reports into a number of Excel workbooks.
I have this process coded so that I can click one button and the entire process will execute end to end. I have a series of text boxes that function as 'indicators' (red - this part failed, green - this part succeeded). As you can imagine, the code for the entire process is HUGE (32 pages when copied into MSWord) and difficult to weed through when I have a problem.
I got it into my mind that I wanted to put the code into a table so that it was much more modular and easier to deal with. I have setup a combo box with the action that I want to take and a second combo box with the report/file/object that I want to work with (ie Delete - Table 2, Acquire - File 1, Export - Report 4). I have been successful at creating the SQL statement to do simple things like del * from tbl_test and execute that from the combo boxes without any issue.
What I need to know is if there is a way to put what is essentially a code snippet into the table (memo field) and then have that vba code execute when I select the matching combos.
IE the code for 'Acquire - File1' is completely VBA code; it maps a network drive, locates the file, downloads the file, and moves it to a directory.
IE the code for 'Scrub - tblMain_Part1' is a combination of vba and sql code; it checks for the existence of a file (vba), if it finds it, it deletes a portion of the main table (sql) and appends the contents of the file it finds (sql), then it updates the monitor to indicate that it is completed (vba). If the file is not found, it changes the monitor box to red and updates a command button caption (vba)
I am NOT a genius with vba, but I hold my own. The thought process I had was that if I can essentially get the code broken into managable chunks in the table, I could call the code smippets in order if I want to run the entire process, or I could just re-execute portions of the code as needed by selecting the action and report/file/object combination.
Any thoughts/ideas are appreciated.
I think it would be best to split the code into Subs. The table you loop through would have a Sub-Name field and a blnSuccess field. Your code would loop though the table running each sub and then updating blnSuccess based on any errors you receive. This would give you queryable result set when you try to see what happened.
Consider using macros. You shouldn't need a table. Also, consider moving your hard-coded SQL to queries.
I think that you shouldn't use a table, just create a module with different subs for each operation. On your button event, after the combo selections, I would do a case statement.
dim strOperation as string
strOperation = me!selectionOne
Select Case strOperation
Case "delete": deleteTable(me!selectionTwo)
Case "export": export(me!selectionTwo)
case "acquire": acquire(me!selectionTwo)
End Select
Of course, you'd have your acquire, delete, and export methods written in a module and have whatever parameters you need for each operation there.
This is just one idea of many that you could use to approach this.
I was going to edit the original answer but this seems to be off on a different tack....
I think it would be best to split the code into functions that return a string if there is an error. The table you loop through would have a strFunction,strError and strObject fields. Your code would loop though the table running each function based on the case statement while passing the strObject as a string and then updating strError based on any errors you receive. You could query the table after this process to see which records have errors in them.
If the button is called cmdRunAll here is the code for it.
Private Sub cmdRunAll_Click()
On Error GoTo ErrHandler
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("tblCode", dbOpenDynaset, dbSeeChanges)
If Not rst.EOF Then
With rst
.MoveFirst
Do While Not .EOF
.Edit
Select Case !strFunction
Case "fExport"
!strError = fExport(!strObject)
End Select
.Update
.MoveNext
Loop
End With
End If
rst.Close
Set rst = Nothing
MsgBox "Processes complete"
Exit Sub
ErrHandler:
Debug.Print Err.Description & " cmdRunAll_Click " & Me.Name
Resume Next
End Sub
Here is a simple sample function
Public Function fExport(strTable As String) As String
On Error GoTo ErrHandler
Dim strError As String
strError = ""
DoCmd.TransferText acExportDelim, , strTable, "C:\users\IusedMyUserNameHere\" & strTable & ".txt"
fExport = strError
Exit Function
ErrHandler:
strError = Err.Description
Resume Next
End Function

Check if Combobox RowSource is Valid

This is somewhat related to this question, but I was hoping there may be a more elegant / simple solution than defining a User-Defined Function.
Background
In essence, this is a common question: I need to dynamically modify the RowSource query of a combobox control on an Access form. The twist is that there is a possibility the resulting query may throw an exception when executed. That is because the source table of the query exists in a different database file which is defined dynamically and may not exist, or even if the file does exist, the desired table or column may not.
Ideally, I would like to be able to catch this problem when the assignment is made, so that the combobox will be disabled and the user cannot invoke the invalid query allowing the end-user to know there is no data available for the field.
For example I would like something like this:
Private Sub UpdateComboRows(src as String)
On Error Goto InvalidQueryError
cmbBox.RowSource = "SELECT [colName] FROM [dBase III;DATABASE=K:\" & src & "].[tblName];"
' Something here to invoke RowSource query and throw error
cmbBox.Enabled = True
Exit Sub
InvalidQueryError:
cmbBox.RowSource = ""
cmbBox.Enabled = False
End Sub
Or something using if-then statements.
Question
Are there any 'sleek' approaches to this, or am I stuck with trying to populate a dummy DAO recordset? Is there some way of invoking the Combobox RowSource query besides the Dropdown event?
Why not take a step back and check first that the database exists with Dir, then check that the column exists in a function. Very roughly.
Function IsDBOk() As Boolean
On Error GoTo Err_Trap
''The default for boolean is false, so
''IsDBOK=False at this point
sFile=Dir("K:\" & src)
If sFile<>"" Then
Dim rs As DAO.Recordset
Set rs = CurrentDB.OpenRecordset("SELECT [colName] " _
& "FROM [dBase III;DATABASE=K:\" _
& src & "].[tblName];")
If Not rs.Eof() Then
''The selection is only okay if the recordset
''contains records, however, you could return
''a different error for each problem
''file missing, column missing, empty recordset
IsDBOk = True
End If
End If
Exit Function
Err_Trap:
''A missing column will give error 3061
''IsDBOk is already set to false
End Function