相关问题:多值字段是个好主意吗?
我知道多值字段类似于多对多关系。在 MS Access 应用程序中替换多值字段的最佳方法是什么?我有一个具有多值字段的应用程序。我不确定如何完全消除这些并以单值字段的形式实现完全相同的逻辑?
当我想将多值关系转移到单值关系时,表关系方面的实现是什么。
谢谢你。
相关问题:多值字段是个好主意吗?
我知道多值字段类似于多对多关系。在 MS Access 应用程序中替换多值字段的最佳方法是什么?我有一个具有多值字段的应用程序。我不确定如何完全消除这些并以单值字段的形式实现完全相同的逻辑?
当我想将多值关系转移到单值关系时,表关系方面的实现是什么。
谢谢你。
以下内容可能比您需要的详细得多,但它适用于初学者。假设您有一个表 MainTable:
ID -> Numeric, primary key
Title -> Text
Surname -> Text
Address -> Text
Country -> Numeric
您可能需要一个标题列表和可供选择的国家/地区。
在 Title 的情况下,将信息存储在表中的字段中并不是最糟糕的事情,因为您只有一列并且数据不太可能更改,并且您可能不会使用数据创建查询.
国家是另一回事,通常你会存储一个数字并有一个查找表。在这种情况下,人们很想使用多值字段。
但是,约定要容易得多。为国家添加另一个表:
ID -> Numeric, primary key
Country -> Text
您可能想调用主表 CountryID 中的相关字段。您现在可以在关系窗口中创建关系,显示 Country 与 MainTable 的关系:
您可以看到选择了 Enforce Referential Integrity,这意味着您必须在 CountryID 字段的国家/地区表中具有 null 或国家/地区。
要查看数据,您可以创建查询:
SELECT
MainTable.ID,
MainTable.Title,
MainTable.Surname,
MainTable.Address,
Country.Country
FROM Country
INNER JOIN MainTable
ON Country.ID = MainTable.CountryID;
但重点是要有一个允许数据输入的表格。您可以使用向导创建表单,但之后,您需要右键单击 CountryID 并将其更改为组合框,或者使用向导添加组合框或列表框。选项 2 可能是最简单的。以下是向导中的大部分步骤:
现在,您的表单上有一个国家/地区的下拉列表。
另请参阅:创建表单以在多个表中添加记录
在 Access 2010 中,当用户输入可能值表中不存在的数据时,有新的方法可以将值添加到组合中。在以前的版本中(虽然我不确定 2007 年),您将使用 Not In List 事件将项目添加到查找表,在 2010 年,您可以选择将 List Items Edit 表单添加到属性表。
这个问题很奇怪,因为它询问的是单值字段,但也询问了表关系。在非常严格的解释中,多值字段 (MVF) 可以替换为单个文本框,其中填充了逗号分隔的项目……不需要表关系。相反,我通过“单值”字段假设问题意味着多表关系中的标准字段,其中每个相关行的每个字段都有一个值。但是每个主记录仍然可以与相关值表中的多行相关,这保留了 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
没有重复行的主表的有用查询将需要创建某种聚合查询(即 Group By、Count 等)。例如,可以在单个查询中完成简单的选择
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 的问题太多,或者如果你想迁移到另一个数据库,那么这种变化将是必要的。
Access 数据库中的 MVF 没有替代品。一些查询技术可以模仿 MVF,但您可能会发现 MVF 功能更胜一筹。1.速度快,非常容易实现。没有代码也没有 SQL。2.它是可视的,因此对用户来说是直观的。有些事情你不能用 MVF 做,所以你真的需要决定什么更重要。