相关问题:Multivalued Fields a Good Idea?
我知道多值字段类似于多对多关系。在MS Access应用程序中替换多值字段的最佳方法是什么? 我有一个具有多值字段的应用程序。我不确定如何完全取消这些并以单值字段的形式实现完全相同的逻辑?
当我想将多值关系移动到单值关系时,表关系方面的实现是什么。
谢谢。
答案 0 :(得分:4)
以下内容可能比您需要的更详细,但它适用于初学者。我们假设你有一张桌子,MainTable:
ID -> Numeric, primary key
Title -> Text
Surname -> Text
Address -> Text
Country -> Numeric
您可能需要一个可供选择的标题和国家/地区列表。
在Title的情况下,将信息存储在表中的字段中并不是最糟糕的事情,因为您有一个列并且数据不太可能更改,并且您可能不会创建查询使用数据。
国家是一个不同的故事,通常你会存储一个数字,并有一个查找表。人们很想使用多值领域。
然而,惯例要容易得多。为国家/地区添加另一个表:
ID -> Numeric, primary key
Country -> Text
您可能希望调用主表CountryID中的相关字段。您现在可以在关系窗口中创建一个关系,显示Country与MainTable的关系:
您可以看到选中了强制参照完整性,这意味着您必须在CountryID字段中的countries表中包含null或country。
要查看数据,您可以创建查询:
SELECT
MainTable.ID,
MainTable.Title,
MainTable.Surname,
MainTable.Address,
Country.Country
FROM Country
INNER JOIN MainTable
ON Country.ID = MainTable.CountryID;
但重点是要有一个允许数据输入的表单。您可以使用向导创建表单,但在此之后,您需要右键单击CountryID并将其更改为组合框或使用向导添加组合框或列表框。选项2可能是最简单的。以下是向导中的大部分步骤:
现在,您的表单上有一个国家/地区的下拉列表。
另请参阅:create form to add records in multiple tables
在Access 2010中,当用户输入可能值表中不存在的数据时,有一些向组合添加值的新方法。在以前的版本中(虽然我不确定2007),您可以使用Not In List事件将项目添加到查找表中,在2010年,您可以选择将列表项编辑表单添加到属性表。
答案 1 :(得分:1)
这个问题很奇怪,因为它询问单值字段,但也询问表关系。在一个非常严格的解释中,多值字段(MVF)可以替换为填充逗号分隔项的单个TextBox ......不需要表关系。相反,我假设“单值”字段表示该问题意味着多表关系中的标准字段,其中每个相关行的每个字段都具有单个值。但是每个主记录仍然可以与相关值表中的多个行相关,这保留了MVF的整个目的。
考虑下面的数据库大纲来说明可能的MVF替代品。我没有包括所有可能的属性或如何创建基本对象,只是创建所需行为的必要条件 - 假设有足够的Access“填空”知识而不用担心基本代码或SQL。
基本结构由三个表组成:1)主表,2)“值列表”表,3)用于定义多对多关系的联结表。
创建表之间的关系。这将需要在表上定义适当的索引(此处未详述)。
(也可以为值表[例如代码表]表创建单独的ID字段,但这只会使以后的查询和控件等复杂化。在这种情况下,联结表将包含另一个ID字段而不是价值直接。)
在标准VBA模块中,创建一个类似
的函数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
没有重复行的主表的有用查询将需要创建某种聚合查询(即分组依据,计数等)。可以在单个查询中进行简单选择,例如
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]);
更复杂的选择可能需要多个查询,一个用于首先选择正确的记录,另一个用于将主表连接到第一个查询。但老实说,这些类型的查询并不比在多值字段上选择所需的查询复杂。实际上,MVF的查询语法是非标准的,并且可能变得相当复杂和混乱,甚至比具有联结表和多对多关系更复杂。在幕后,Access基本上和我概述的一样,但由于它隐藏了如此多的细节,因此使得一些查询变得更加困难。
关于表单上的多值表示和选择,完全不可能模仿多值ComboBox - 主要是因为基本的Access Combobox没有能够显示复选框的多选选项。但是,可以使用属性[Multi Select] = Simple填充非绑定ListBox。在Form_Load事件上,使用ListBox.AddItem方法将可用值(例如,示例表中的代码)添加到列表框中。然后在Form_Current,Form_AfterUpdate,Form_Undo事件中,可以添加代码以显示和/或保存所选值。这需要更多的代码,这可能超出了这里的范围。
从技术上讲,问题是将MVF“移动”到另一个实现。要点是使用MVF列表中的相同值填充值表(例如,示例中的代码表)。这可能是一个手动过程,但取决于如何填充MVF的ComboBox。然后编写一个查询,将每个MFV复制到联结表(例如[客户代码])中,用于相同的主记录,例如
INSERT INTO [Customer Codes] ( CustomerID, Code )
SELECT Customer.CustomerID, Customer.TestMVF.Value
FROM Customers
WHERE (((Customers.TestMVF.Value) Is Not Null));
完整的实现绝对不是一个简单的任务,但是如果你发现MVF有太多问题,或者你想要迁移到另一个数据库,那么就需要进行这种改变。
答案 2 :(得分:0)
Access数据库中没有MVF替代品。一些查询技术可以模仿MVF,但您可能会发现MVF功能更优越。 1.它快速且易于实施。没有代码也没有SQL。 2.它是视觉的,因此对用户来说是直观的。有些事情你不能用MVF做,所以你真的需要决定什么是更重要的。