【问题标题】:Access - Best way to return employee list based on another table访问 - 基于另一个表返回员工列表的最佳方式
【发布时间】:2021-05-24 22:33:52
【问题描述】:

希望我能以某种方式解释这一点,以便有人能够理解我想要实现的目标并能够提供可能的解决方案。

我正在创建一个数据库,用于管理工作场所的健康和安全。我创建了一张表来存储员工 - “表:员工”。该表具有常用字段(名字、姓氏等),但具体包含以下字段:“部门”(员工可以在其间移动时选择多项)、“其他能力”(例如叉车、订单拣选员等)。(再次选择多个选择))和“性别”。

我有第二个表格(“表格:工具箱对话”),系统存储工具箱对话(由用户通过表单创建。“表格:工具箱对话”)。工具箱演讲的预期接收者通常仅限于一个或多个部门,或者可能只是所有叉车司机或所有一种性别。当用户创建新的工具箱谈话(记录)时,他们会在表格(Form: Toolbox Talk)中从下拉列表中选择相应的变量(部门、能力、性别)。 (请注意,工具箱谈话有时可能与不止一个相关。)

我想要实现的是如何为每个工具箱谈话创建一个查询,它将只返回需要参与工具箱谈话的员工。

例如: 假设所有在“仓储”工作的“女性”员工都需要进行工具箱谈话。 然后,我希望我的数据库在表单上的数据表子表单中 - “表单:工具箱对话”返回所有女性员工并被标记为能够在仓储部门工作。

我只想补充一点,我想避免预期的系统用户使用功能区上的过滤器按钮,如果可能的话,我的偏好是使用查询或 vba。

到目前为止我所做的尝试:

1. 我创建了一个查询(“查询:EmployeesperToolboxTalk”)并添加了两个表(“查询:EmployeesExtended”和“查询:ToolboxTalksExtended”)。我尝试在相关字段之间创建连接(例如,Gender to Gender、Department to Department 等),但这对于连接属性 1、2 或 3 都不起作用。 如果我将加入限制为仅说部门,那么这似乎可以满足我的要求,但它不包括其他两个变量,这并不是我真正想要的工作方式。

SELECT [Query: EmployeesExtended].[Employee Name], [Query: EmployeesExtended].Department, [Query: ToolboxTalksExtended].[Toolbox Talk], [Query: ToolboxTalksExtended].ToolTalkID, [Query: ToolboxTalksExtended].RecipientVariables
FROM [Query: EmployeesExtended] INNER JOIN [Query: ToolboxTalksExtended] ON ([Query: EmployeesExtended].Gender = [Query: ToolboxTalksExtended].RelatedGender) AND ([Query: EmployeesExtended].AdditionalCompetency.Value = [Query: ToolboxTalksExtended].RelatedCompetency.Value) AND ([Query: EmployeesExtended].Department.Value = [Query: ToolboxTalksExtended].RelatedDepartment.Value);

2. 之后,我创建了一个联合查询,将所有不同的变量合并为一个:

SELECT [Table: Competencies].Competency
FROM [Table: Competencies];
UNION 
SELECT [Table: Departments].Department
FROM [Table: Departments];
UNION SELECT [Table: Gender].Gender
FROM [Table: Gender];

然后我在表中添加了一个字段“RecipientVariables”:“Table: Toolbox Talks”,并将行源设置为:

SELECT [Query: RecipientVariables].Competency
FROM [Query: RecipientVariables];

然后我创建了一个从“RecipientVariables”到 Departments、AdditionalCompetency 和 Gender 的联接:

SELECT [Query: EmployeesExtended].[Employee Name], [Query: EmployeesExtended].Department, [Query: ToolboxTalksExtended].[Toolbox Talk], [Query: ToolboxTalksExtended].ToolTalkID, [Query: ToolboxTalksExtended].RecipientVariables
FROM [Query: ToolboxTalksExtended] INNER JOIN [Query: EmployeesExtended] ON ([Query: ToolboxTalksExtended].RecipientVariables.Value = [Query: EmployeesExtended].Department.Value) AND ([Query: ToolboxTalksExtended].RecipientVariables.Value = [Query: EmployeesExtended].AdditionalCompetency.Value) AND ([Query: ToolboxTalksExtended].RecipientVariables.Value = [Query: EmployeesExtended].Gender);

这使用连接属性 1、2 或 3 不返回任何结果。

3.我尝试的最后一件事是从我的员工表(“表:员工”)创建第二个联合查询:

SELECT [Table: Employees].AdditionalCompetency.Value
FROM [Table: Employees];
UNION
SELECT [Table: Employees].Gender
FROM [Table: Employees];
UNION SELECT [Table: Employees].Department.Value
FROM [Table: Employees];

然后,我在员工表中添加了一个新字段:“AreasofCompetency”,并将行来源设置为: "查询:EmployeeVariables"

这也行不通。

我现在不知道下一步该尝试什么。 也许我想做的事情是不可能的,或者比我意识到的要容易得多。

如果有人可以提供一些指导或提供替代建议,我将不胜感激。如果需要任何其他信息,请告诉我,我很乐意提供。

非常感谢。

【问题讨论】:

  • 审查数据库设计,特别是表规范化。表格不必是用户友好的,这正是表单和报告的用途。

标签: ms-access


【解决方案1】:

根据我的评论,首先规范您的表结构。例如:

然后创建一个查询,选择与员工相关的所有内容。这就是一切。选择该查询并单击创建表单,访问将为您创建一个表单: 标题中的未绑定组合框和未绑定列表框实际上还没有,并且表单显示了记录源中的每个变量,因此对用户不友好。将组合框和列表框添加到您要筛选员工的每个变量的标题中。还可以根据需要删除和/或移动标签和文本框。我得到了:

然后您要编辑各种未绑定控件的更新后事件以过滤记录。例如见Filter form based on two combo box selections

Private Sub cmbCompetency_AfterUpdate()
'cheap example hookup, same code for lstDepartments
Me.Filter = "EmployeesCompetencies.CompetencyID = " & cmbCompetency & " AND EmployeesDepartments.DepartmentID = " & cmbDepartment
Me.FilterOn = True
End Sub

这会让你:

【讨论】:

  • 我可能需要您填写一些空白,因为我对按照您的建议进行操作感到非常困惑。我根据您的示例创建了表格,但我无法弄清楚它们是如何交互的。我的意思是我有一个表格,我可以在其中输入我的员工(表格:员工资料),该表格链接到表:员工。我可以弄清楚如何插入一个组合框,该组合框具有表的行源:部门。我无法弄清楚这些信息是如何存储在表中的:EmployeesDepartments?按照您的建议将它们组合成一个查询只会返回一个空白表。
  • 您输入到表格中的数据很可能是格式错误的。从某种意义上说,一个查询将几个表重新组合成一个表。但默认情况下,如果新表中的任何列为空白,则整行为空白。因此,一个空表是查询结果。将其视为一个学习难题。从简单的示例表、简单的数据和简单的查询开始,并确保您得到的内容看起来正确。处理您拥有的多对多关系(提示)。
  • 以防万一,如果表之间的关系没有连接起来,那么您也会得到一个空白查询。在这种情况下,要么在每个查询中添加关系,要么最好在数据库工具关系下一劳永逸地完成。 (将一张表的主键拖到另一张表对应的外键上)
  • 您好 Mazoula,对不起,我花了这么长时间才回复您。我按照您的建议做了,并将其视为一个学习难题。根据您的示例,我用一些非常简单的表创建了一个新数据库,然后我解决了 - 谢谢。
  • 然后我将学到的知识应用到我的开发数据库中,并取得了一些成功。我的下一个问题是字段为空白的情况。所以每个员工都会被分配一个部门,这是给定的。然而,并非每个人都一定会被分配一种能力。在这种情况下,这些人不会出现在我的查询 (Query: ToolboxTalk) 和表单 (Form: ToolboxTalk) 中。有没有办法让查询显示所有员工,即使他们没有被分配能力?你有什么其他的建议来解决这个问题吗?我可能必须创建每个人都能获得的默认能力?
【解决方案2】:

数据库设计

首先,您需要摆脱多值列。出于多种原因,使用多值列从来都不是一个好主意,当相同的值出现在两个或多个表中并且您想要连接这些列时,它们是一个特别糟糕的主意。这是一个规范化的数据库设计。

部门表

Column Name Data type Required Description
Id Autonumber Y Primary key
Name Short text Y

能力表

Column Name Data type Required Description
Id Autonumber Y Primary key
Name Short text Y

员工表

Column Name Data type Required Description
Id Autonumber Y Primary key
First_Name Short text Y
Last_Name Short text Y
Gender Short text Y

Employee_Department 表

Column Name Data type Required Description
Employee_Id int Y Foreign key references Employee (Id)
Department_Id int Y Foreign key references Department (Id)

Employee_Competency 表

Column Name Data type Required Description
Employee_Id int Y Foreign key references Employee (Id)
Competency_Id int Y Foreign key references Competency (Id)

Toolbox_Talk 表

Column Name Data type Required Description
Id Autonumber Y Primary key
Title Short text Y
Target_Gender Short text N Null indicates no specific target gender (i.e., any value of gender)

Toolbox_Talk_Target_Department 表

Column Name Data type Required Description
Toolbox_Talk_Id int Y Foreign key references Toolbox_Talk (Id)
Department_Id int Y Foreign key references Department (Id)

Toolbox_Talk_Target_Competency 表

Column Name Data type Required Description
Toolbox_Talk_Id int Y Foreign key references Toolbox_Talk (Id)
Competency_Id int Y Foreign key references Competency (Id)

查询设计

您的查询选择条件过于复杂,无法在 SQL 中表示,但您可以使用 VBA 在内存中构建您的查询,然后像这样执行它。

Dim db As Database
Dim rs As Recordset
Dim sql As String
Dim whereClause As String

Set db = CurrentDb
Set rs = db.OpenRecordset(sql, dbOpenForwardOnly, dbReadOnly)
Do Until rs.EOF
    ' Process recordset
    rs.MoveNext
    DoEvents
Loop
rs.Close
Set rs = Nothing

sql 语句应该选择所有符合谈话选择标准的员工。我假设您希望每个员工只出现一次,即使他们符合多个标准。 sql语句如下所示。

sql = "Select E.Id, E.First_Name, E.Last_Name "
sql = sql & "From Employee E "
sql = sql & "Inner Join ("
sql = sql & "Select Distinct Id "
sql = sql & "From Employee "
sql = sql & whereClause
sql = sql & ") As Qry1 "
sql = sql & "On E.Id = Qry1.Id "

查询选择标准

给定一个 Toolbox_Talk_Id,你可以像这样得到目标性别。

Dim targetGender As Variant

targetGender = DLookup("Target_Gender", "Toolbox_Talk", "Id = " & Toolbox_Talk_Id)

你可以这样获取目标部门。

Dim targetDepartments As Collection

Set targetDepartments = New Collection

Set rs = db.OpenRecordset("Select Department_Id From Toolbox_Talk_Target_Department Where Toolbox_Talk_Id = " & Toolbox_Talk_Id, dbOpenForwardOnly, dbReadOnly)
Do Until rs.EOF
    targetDepartments.Add rs!Department_Id.Value
    rs.MoveNext
    DoEvents
Loop
rs.Close
Set rs = Nothing

您可以通过同样的方式查询 Toolbox_Talk_Target_Competency 表来获得目标能力。

鉴于演讲的目标性别、部门和能力,您现在可以组装查询的 where 子句。

如果谈话目标性别不为空,则仅选择符合该性别的员工。

If Not IsNull(targetGender) Then
    If Len(whereClause) = 0 Then
        whereClause = "WHERE "
    Else
        whereClause = whereClause & " AND "
    End If
    whereClause = whereClause & "Employee.Gender = " & Chr(34) & targetGender & Chr(34)
End If

如果指定了一个或多个目标部门,则通过 Employee_Department 表仅选择与这些部门关联的员工。

If targetDepartments.Count > 0 Then
    If Len(whereClause) = 0 Then
        whereClause = "WHERE "
    Else
        whereClause = whereClause & " AND "
    End If
    If targetDepartments.Count = 1 Then
        ' one department
        whereClause = whereClause & "EXISTS (Select 1 From Employee_Department Where Employee_Id = Employee.Id And Department_Id = " & targetDepartments(1) & ") "
    Else
        ' two or more departments
        whereClause = whereClause & "EXISTS (Select 1 From Employee_Department Where Employee_Id = Employee.Id And Department_Id In (" & targetDepartments(1)
        For idx = 2 To targetDepartments.Count
            whereClause = whereClause & ", " & targetDepartments(idx)
        Next idx
        whereClause = whereClause & ")) "
    End If
End If

最终的结果应该是这样的 sql 语句。

Select E.Id, E.First_Name, E.Last_Name 
From Employee E 
Inner Join (
Select Distinct Id 
From Employee 
Where Employee.Gender = "NB"
And EXISTS (Select 1 From Employee_Department Where Employee_Id = Employee.Id And Department_Id In (3, 4))
) As Qry1 
On E.Id = Qry1.Id 

【讨论】:

    猜你喜欢
    • 2021-01-15
    • 1970-01-01
    • 2015-08-25
    • 1970-01-01
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多