MS Access 中多值字段的替代方案
Posted
技术标签:
【中文标题】MS Access 中多值字段的替代方案【英文标题】:Alternative to multi-valued fields in MS Access 【发布时间】:2012-11-22 04:20:24 【问题描述】:相关问题:Multivalued Fields a Good Idea?
我知道多值字段类似于多对多关系。在 MS Access 应用程序中替换多值字段的最佳方法是什么? 我有一个具有多值字段的应用程序。我不确定如何完全消除这些并以单值字段的形式实现完全相同的逻辑?
当我想将多值关系转移到单值关系时,表关系的实现方式是什么。
谢谢。
【问题讨论】:
我不会说它们类似于多对多关系,我没有详细阅读它们,但不要想象您可以将多值字段用于 PK 和 FK .你能告诉我们更多关于它们在你的数据库中的广泛使用,有多少表、字段、值等。看来你需要编写一些 VBA 逻辑来去除它们,但首先我们需要更多的结构细节。跨度> 多值字段确实像多对多关系,这与马特唐南的假设相反。多值字段本身不能是 PK 和 FK,但它们由 Access“在幕后”通过使用单独的系统值和联结表实现。 【参考方案1】:以下内容可能比您需要的详细得多,但它是为初学者准备的。假设您有一个表 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 可能是最简单的。以下是向导中的大部分步骤:
现在您的表单上有一个国家/地区的下拉列表。
另请参阅:create form to add records in multiple tables
在 Access 2010 中,当用户输入可能值表中不存在的数据时,有新的方法可以将值添加到组合中。在以前的版本中(尽管我不确定 2007 年),您将使用 Not In List 事件将项目添加到查找表中,在 2010 年,您可以选择将 List Items Edit 表单添加到属性表。
【讨论】:
感谢 Remou 的回答。假设对于您显示的表格,我想要记录如下。 ID:1 标题:先生姓氏:Watson 就国家而言,我想将 2 个国家与此记录相关联(如果是多值国家字段,我可以选择存储这两个国家的名称在同一国家/地区字段中。)。我们如何避免使用多值字段;仍然从数据库中获得相同的行为。有没有办法实现这种行为? 是的,您需要一个联结表。这将包含 PersonID 和 CountryID 以及组合字段上的唯一索引。例如:***.com/questions/1356492/… 这不是一个答案,并且不允许用户选择多个值进行选择,因此不是多值。【参考方案2】:这个问题很奇怪,因为它询问的是单值字段,但也询问了表关系。在非常严格的解释中,多值字段 (MVF) 可以替换为单个文本框,其中填充了逗号分隔的项目……不需要表关系。相反,我通过“单值”字段假设问题意味着多表关系中的标准字段,其中每个相关行的每个字段都有一个 single 值。但是每个主记录仍然可以与相关值表中的多行相关联,这保留了 MVF 的全部用途。
考虑下面的数据库大纲来说明 MVF 的可能替代品。我没有包括所有可能的属性或如何创建基本对象,只是创建所需行为所必需的——假设有足够的 Access 知识来“填补空白”并且不担心基本代码或 SQL。
基本结构由三个表组成:1)主表,2)“值列表”表,3)用于定义多对多关系的联结表。
客户表 客户 ID:自动编号,主要 客户名称:短文本 代码表 代码:短文本,长度5,主键 说明:短文本 [客户代码] 表 客户 ID:长 代码:短文本创建表之间的关系。这将需要在表上定义适当的索引(此处不详)。
客户表到 [客户代码] 表 CustomerID -> CustomerID 字段(启用强制完整性) 代码表到 [客户代码] 表 代码 -> 代码字段(启用强制完整性)(也可以为值表 [例如代码表] 表创建一个单独的 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 本质上与我所概述的相同,但由于它隐藏了太多细节,使得一些查询变得更加困难。
关于表单上的多值显示和选择,完全模仿多值组合框是不可能的——主要是因为基本的 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有太多问题或者你想迁移到另一个数据库,这种变化是有必要了解的。
【讨论】:
【参考方案3】:Access 数据库中的 MVF 没有替代品。一些查询技术可以模仿 MVF,但您可能会发现 MVF 功能更胜一筹。 1.速度快,实现起来非常容易。没有代码也没有 SQL。 2.它是可视的,因此对用户来说是直观的。有些事情你不能用 MVF 做,所以你真的需要决定什么更重要。
【讨论】:
“没有代码和没有 SQL”没有用处,因为任何 Access 数据库中的代码和 SQL 数量取决于最终所需/所需的行为。很多事情可以在没有代码的情况下完成,但很多事情需要代码和/或使用 SQL ——这是一个非常通用的语句,不仅限于 MVF。说“有些事情是你不能做的”也是相当无用的,因为准确地找出限制是什么并非易事。最后,确实可以使用联结表和自定义函数复制多值字段的大部分行为以方便查询等。 MVF 控件允许用户在表单中添加多项选择 UI,并且无需代码即可。我所知道的几乎没有像 Access 这样的无代码系统。此功能允许非开发人员创建通常需要昂贵的开发人员的应用程序。每个人都必须学会使用标准变速器驾驶汽车的想法是愚蠢的,在这种情况下也是愚蠢的。这是一项允许人们在没有代码或 SQL 的情况下构建系统的功能。接下来是什么,建议大家学汇编来用电脑?接下来是什么,强制代码布局表单? 替换是与联结表的多对多关系,从标准 RDB 设计中得知,因为它们在功能上确实是等效的。 Access 使用内部联结表实现 MVF,只是向用户隐藏了增加的复杂性。我相信 MVF 的唯一限制与与其他 DBMS 的集成或移植到其他 DBMS 有关,因为需要首先重建联结表。也许未来版本的 Access 会自动执行此操作,但目前,如果数据要在 Access 之外使用,则绝对应该考虑额外的编程工作。 @Albert 我强调的是 MVF 不应该被过度简化,仅此而已。除非它是一个极其简单的数据库,否则很可能有人会想要超越无代码的“多选 UI”。我现在已经花了一年时间使用 MVF 开发和更新数据库。否则,通常可以使用 Access 设计器完成的简单查询(即“无 SQL”)并不总是可以使用 MVF,特别是更新查询和插入查询,尤其是。与连接。即使 MVF 不是正在更新的字段...通常甚至根本无法在查询中引用它而不会导致问题。以上是关于MS Access 中多值字段的替代方案的主要内容,如果未能解决你的问题,请参考以下文章
绑定到 Sharepoint 多值字段的组合框的 MS Access 全选复选框
MS Access 2010 - 使用 RIGHT JOIN 的 SQL 查询 - 返回太多值