Alternative to multi-valued fields in MS Access

后端 未结 3 1015
梦谈多话
梦谈多话 2021-02-10 03:00

Related question: Multivalued Fields a Good Idea?

I know that multi-valued fields are similar to many-to-many relationship. What is the best way to replace multi-valued

相关标签:
3条回答
  • 2021-02-10 03:02

    The question is rather odd since it asks about a single-value field, but also asks about table-relationships. In a very strict interpretation, a multi-value field (MVF) could be replaced with a single TextBox filled with comma-separated items... no table-relationships required. Instead, I assume by "single-value" field that the question means standard fields in a multi-table relationship, in which each field of each related row has a single value. But each primary record can still be related to multiple rows in the related value table, which preserves the whole purpose of the MVF.

    Consider the database outline below to illustrate a possible replacement for the MVF. I'm not including every possible property or how to create basic object, just what's necessary for creating desired behavior--assuming enough knowledge of Access to "fill in the blanks" and no fear of basic code or SQL.

    The basic structure consists of three tables: 1) Primary table, 2) "value list" table, 3) junction table used to define many-to-many relationship.

    • Customer Table
      CustomerID: autonumber, primary
      CustomerName: short text
    • Codes Table
      Code: short text, length 5, primary key
      Description: short text
    • [Customer Codes] Table
      CustomerID: long
      Code: short text

    Create relationships between the tables. This will require appropriate indexes defined on the tables (not detailed here).

    • Customer Table to [Customer Codes] Table
      CustomerID -> CustomerID fields (with enforce integrity enabled)
    • Code Table to [Customer Codes] Table
      Code -> Code fields (with enforce integrity enabled)

    (A separate ID field could also be created for the values table [e.g. Codes Table] table, but that just complicates later queries and controls, etc. In such a case, the junction table would contain another ID field and not the value directly.)

    In a standard VBA module, create a function like

    Public Function GetCodeList(ByVal CustomerID As Integer) As String
       Dim sSQL As String
       Dim qry As QueryDef
       Dim rs As Recordset2
    
       sSQL = "PARAMETERS [CustID] LONG;" & _
           " SELECT * FROM [Customer Codes] WHERE [CustomerID] = [CustID]"
       Set qry = CurrentDb.CreateQueryDef("", sSQL)
       qry.Parameters("CustID") = CustomerID
       Set rs = qry.OpenRecordset(dbOpenForwardOnly, dbReadOnly)
    
       Dim sCodes As String
       sCodes = ""
       Dim bFirst As Boolean
       bFirst = True
    
       Do Until rs.EOF
          sCodes = sCodes & IIf(bFirst, "", ",") & rs("Code")
          bFirst = False
          rs.MoveNext
       Loop
    
       rs.Close
       qry.Close
    
       GetCodeList = sCodes
    End Function
    

    Useful queries of the primary table without duplicate rows will require creating some sort of aggregate queries (i.e. Group By, Count, etc.). Simple selection could be done in a single query, for example

    SELECT Customer.CustomerID, Customer.[CustomerName], GetCodeList([CustomerID]) AS Codes, Count(Customer.CustomerID) AS CountOfID
    FROM Customer LEFT JOIN [Customer Codes] ON Customer.ID = [Customer Codes].CustomerID
    WHERE ((([Customer Codes].Code)="Current" Or ([Customer Codes].Code)="Free"))
    GROUP BY Customer.ID, Customer.[CustomerName], GetCodeList([ID]);
    

    More complicated selection may require multiple queries, one to first select the proper records, then another to join the primary table to the first query. But honestly, these types of queries are no more complicated than what can be required to select on Multi-Valued Fields. In fact, the query syntax for MVF is non-standard and can get rather complicated and confusing, even more than having a junction table and many-to-many relationships. Behind the scenes, Access is essentially doing the same thing as I've outlined, but because it hides so much detail it make some queries even more difficult.

    Regarding multi-value presentation and selection on a form, mimicking the multi-valued ComboBox exactly is not possible--mainly because the basic Access Combobox does not have a multi-selection option with the ability to show checkboxes. However, one can populate a non-bound ListBox with property [Multi Select] = Simple. On the Form_Load event, add available values (e.g. Code from the example table) to the listbox using ListBox.AddItem method. Then in the Form_Current, Form_AfterUpdate, Form_Undo events, one can add code to show and/or save the selected values. This requires more code which is probably beyond the scope here.

    Technically the question asked about "moving" a MVF to another implementation. The gist is to populate the values table (e.g. Code table in the example) with the same values in the MVF list. This could be a manual process, but depends on how the MVF's ComboBox is populated. Then write a query which copies each MFV into the junction table (e.g. [Customer Code]) for the same primary record, something like

    INSERT INTO [Customer Codes] ( CustomerID, Code )
    SELECT Customer.CustomerID, Customer.TestMVF.Value
    FROM Customers
    WHERE (((Customers.TestMVF.Value) Is Not Null));
    

    A full implementation is definitely not a simple task overall, but if you find too many problems with MVFs or if you are wanting to migrate to another database, this kind of change will be necessary to understand.

    0 讨论(0)
  • 2021-02-10 03:08

    The following is probably far more detailed than you need, but it is intended for a beginner. Let us say you have a table, MainTable:

    ID -> Numeric, primary key
    Title -> Text
    Surname -> Text
    Address -> Text
    Country -> Numeric
    

    You will probably want a list of titles and countries from which to select.

    In the case of Title, it would not be the worst thing to store the information in a field in a table, because you have a single column and the data is unlikely to change, and you probably will not be creating a query using the data.

    Country is a different story, conventionally you would store a number and have a look-up table. It is the kind of situation where people are tempted to use a multi-value field.

    However, convention is a lot easier. Add another table for country:

    ID -> Numeric, primary key
    Country -> Text
    

    You might like to call the related field in the main table CountryID. You can now create a relationship in the relationship window showing how Country relates to MainTable:

    relationship

    You can see that Enforce Referential Integrity is selected, which means that you must have null or a country from the countries table in the CountryID field.

    To view the data, you can create a query:

    SELECT 
        MainTable.ID, 
        MainTable.Title, 
        MainTable.Surname, 
        MainTable.Address, 
        Country.Country
    FROM Country 
    INNER JOIN MainTable 
    ON Country.ID = MainTable.CountryID;
    

    query

    But the main point is to have a form that allows data entry. You can create a form using the wizards, but after that, you either need to right-click CountryID and change it to a combobox or add a combobox or listbox using the wizard. Option 2 is probably the easiest. Here are most of the steps from the wizard:

    combo1 combo2 combo3 combo4 combo5

    You now have a dropdown list of countries on your form.

    form

    See also: create form to add records in multiple tables

    In Access 2010, there are new ways of adding values to combos when the user enters data that does not exist in the table of possible values. In previous versions (although I am not sure about 2007), you would use the Not In List event to add items to a look-up table, in 2010, you have a choice of adding a List Items Edit form to the property sheet.

    add item to lookup table1 add item to lookup table2

    0 讨论(0)
  • 2021-02-10 03:12

    There is no replacement for MVFs in an Access database. Some query techniques can mimic MVFs but you may find MVF functionality to be superior. 1. It is fast and very easy to implement. No code and no SQL. 2. It is visual and therefore it is intuitive for the user. There are some things that you cannot do with an MVF so you really need to decide what is more important.

    0 讨论(0)
提交回复
热议问题