Access宽表转长表后关联查询返回不匹配记录问题排查
问题根因
1. 员工ID查询SQL语法错误,导致外键匹配完全失效
CODE1中构造员工ID查询的SQL遗漏了FirstName字段名,最终生成的SQL为:
SELECT ID FROM tbl_EmployeeInformation WHERE LastName = "传入的姓" AND "传入的名"
在Access SQL逻辑中,非空字符串常量会被判定为True,因此该条件等价于仅按LastName过滤员工。如果存在多名同姓员工,OpenRecordset默认返回查询结果的第一条记录ID,完全不校验名字,导致存入tbl_CompletedTrainings的Employee外键从根源上就是错的。
正确写法参考:
Set qryGetNameID = db.OpenRecordset("SELECT ID FROM tbl_EmployeeInformation WHERE LastName = " & Chr(34) & lname & Chr(34) & _ " AND FirstName = " & Chr(34) & fname & Chr(34) & ";")
2. 重复调用AddNew生成脏数据
CODE1写入长表时连续调用了两次rsutab.AddNew:
rsutab.AddNew ' 第一次生成新行,未赋值 Debug.Print lname Debug.Print fname ' 省略调试打印代码 rsutab.AddNew ' 第二次生成新行,丢弃上一行未保存的内容 rsutab("Employee") = qryGetNameID.Fields(0) ' 省略赋值逻辑 rsutab.Update
第一次AddNew生成的空行未赋值就被丢弃,部分场景下会生成多余的空值/默认值记录,也是数据异常的直接诱因之一,删除多余的第一次AddNew即可。
3. 培训ID偏差的原因
你观察到的培训ID比预期小2的问题,是因为培训ID查询SQL未指定排序规则,当存在近似匹配的培训名称(比如名称带多余空格、后缀),或查询结果默认按非主键字段排序时,OpenRecordset返回的第一条记录的AutoID就会和预期不符。
建议给查询SQL增加排序规则,同时加EOF判断避免匹配不到时报错:
Set qryGetTrainingNameID = db.OpenRecordset("SELECT AutoID FROM Trainings WHERE [Training Name] = " & Chr(34) & namevar & Chr(34) & " ORDER BY AutoID;") If qryGetTrainingNameID.EOF Then ' 可在此处增加匹配不到的处理逻辑,比如跳过当前记录、打印日志 GoTo NextLoop End If
4. 空值判断逻辑错误
原代码的非空判断使用了Or逻辑:
If rsxtab.Fields(loopint) <> "" Or Not IsNull(rsxtab.Fields(loopint))
该逻辑会把Null值误判为有效内容,应该改为And逻辑:
If Not IsNull(rsxtab.Fields(loopint)) And rsxtab.Fields(loopint) <> ""
你看到的查询结果日期一致、其他字段不匹配的现象,正好对应上述问题:日期是直接从宽表中读取存入长表的,没有经过关联匹配,所以不会出错;而员工、培训字段依赖错误的外键查询逻辑存入,关联后自然返回不匹配的记录。
内容的提问来源于stack exchange,提问作者Christopher J. Joubert
相关产品推荐
相关产品推荐

