Ms access 基于ID对列访问行数据
我有一个用于员工培训的MS Access数据库,每个员工每年都要上两次课 该类的表如下所示:Ms access 基于ID对列访问行数据,ms-access,Ms Access,我有一个用于员工培训的MS Access数据库,每个员工每年都要上两次课 该类的表如下所示: EmployeeID ClassDate ClassHours 1 1/1/2011 8 1 7/31/2011 7 2 2/1/2011 8 2 8/31/2011 7 3 3/1/2011 8 3 9/30/2
EmployeeID ClassDate ClassHours
1 1/1/2011 8
1 7/31/2011 7
2 2/1/2011 8
2 8/31/2011 7
3 3/1/2011 8
3 9/30/2011 7
EmployeeID ClassDate_1 ClassHours_1 ClassDate_2 ClassHours_2
1 1/1/2011 8 7/31/2011 7
2 2/1/2011 8 8/31/2011 7
3 3/1/2011 8 9/30/2011 7
我希望表格的格式如下所示:
EmployeeID ClassDate ClassHours
1 1/1/2011 8
1 7/31/2011 7
2 2/1/2011 8
2 8/31/2011 7
3 3/1/2011 8
3 9/30/2011 7
EmployeeID ClassDate_1 ClassHours_1 ClassDate_2 ClassHours_2
1 1/1/2011 8 7/31/2011 7
2 2/1/2011 8 8/31/2011 7
3 3/1/2011 8 9/30/2011 7
如何编写查询以基于EmployeeID将第二个类日期和小时字段移动到同一行
我已经通过这个网站进行了研究,所有可能的解决方案似乎都过于复杂,因为我正在尝试实现
非常感谢你的帮助
谢谢您必须使用子选择创建查询
SELECT
X.EmployeeID,
X.d1 AS ClassDate_1, ec1.ClassHours AS ClassHours_1,
X.d2 AS ClassDate_2, ec2.ClassHours AS ClassHours_2
FROM
( (SELECT e.EmployeeID, Min(e.ClassDate) AS d1, Max(e.ClassDate) AS d2
FROM employee_classes AS e
GROUP BY e.EmployeeID) AS X
INNER JOIN employee_classes AS ec1
ON X.EmployeeID = ec1.EmployeeID AND X.d1 = ec1.ClassDate
)
INNER JOIN employee_classes AS ec2
ON X.EmployeeID = ec2.EmployeeID AND X.d2 = ec2.ClassDate;
或者,您可以将嵌套的select存储为一个查询,我们称之为query1:
然后在第二个查询中使用它
SELECT
X.EmployeeID,
X.d1 AS ClassDate_1, ec1.ClassHours AS ClassHours_1,
X.d2 AS ClassDate_2, ec2.ClassHours AS ClassHours_2
FROM
( query1 AS X
INNER JOIN employee_classes AS ec1
ON X.EmployeeID = ec1.EmployeeID AND X.d1 = ec1.ClassDate
)
INNER JOIN employee_classes AS ec2
ON X.EmployeeID = ec2.EmployeeID AND X.d2 = ec2.ClassDate;
如果不显示小时数,那就容易多了
SELECT e.EmployeeID, Min(e.ClassDate) AS ClassDate_1, Max(e.ClassDate) AS ClassDate_2
FROM employee_classes AS e
GROUP BY e.EmployeeID
确实有一个更简单的解决方案,但是它假设表是按EmployeeID和ClassDate排序的。这种假设是不安全的,因为不能保证自然排序顺序。Access可以随时决定以不同的方式重新组织记录
SELECT
EmployeeID,
First(ClassDate) AS ClassDate_1, First(ClassHours) AS ClassHours_1,
Last(ClassDate) AS ClassDate_2, Last(ClassHours) AS ClassHours_2
FROM
employee_classes
GROUP BY
EmployeeID
ORDER BY
EmployeeID;
在这里,再次选择一个子项也会有所帮助
SELECT
EmployeeID,
First(ClassDate) AS ClassDate_1, First(ClassHours) AS ClassHours_1,
Last(ClassDate) AS ClassDate_2, Last(ClassHours) AS ClassHours_2
FROM
(SELECT * FROM employee_classes ORDER BY EmployeeID, ClassDate)
GROUP BY
EmployeeID
ORDER BY
EmployeeID;
但是,无论是子查询还是第二个查询都是必需的。这取决于您计划如何处理结果(如果它们只是为了显示)。这里是一个交叉表查询,它在值单元格中包含类日期和小时,在日期后的括号中包含小时
TRANSFORM Last([ClassDate] & " (" & [ClassHours] & ")") AS Details
SELECT Classes.EmployeeId
FROM Classes
GROUP BY Classes.EmployeeId
PIVOT "Class " & (DCount("[ClassNumber]","[Classes]","[ClassDate]<#" & Format$([ClassDate],"dd-mmm-yyyy") & "# AND [EmployeeId]=" & [EmployeeId])+1);
这将允许任何数量的课程,而不仅仅是每个教师两个
来源:我不会做这样的表-它违反了数据库规范化的第一条规则。您可以保留一个员工表和一个类表,并编写一个查询来提供所需的结果。这就是我想做的。保持原始表不变,但创建一个查询,将EmployeeID的公共字段移动到同一行。我只是不知道如何编写查询来获得结果。非常感谢Olivier。我用了你的第一个例子,效果很好。然而,有时员工只参加一次课程,并且只有一行条目。如何实现WHERE子句来检查ClassDate_2 ClassDate_1?IIfX.d1=X.d2,null,X.d2作为ClassDate_2,IIfec1.ClassHours=ec2.ClassHours,null,ec2.ClassHours作为ClassHours_2。但是,该解决方案最多只适用于每个员工两个级别。如果你有更多的类,你将不得不使用ChrisPadgham的解决方案。Olivier,非常感谢你的帮助。这个解决方案完全符合我的需要。我只需要将第二个IIF语句更改为与第一个IIF语句具有相同的表达式。上课时间总是一样的,所以我把它改成了检查上课日期是否与获取时间的条件相同。再次感谢您的解决方案。