Access 或 SQL:需要帮助从字段名称在查询中动态选择的字段返回数据

问题描述

我在 sql 中设置了一个数据库,就像一个有 50 列的电子表格。除员工姓名外,字段名称将是 Machine01、Machine02 等,并且记录将包括在每台机器上认证的日期。我将 Access 用作传统前端,因为已经有很多人使用它进行编码和培训。

我将如何编写一个查询来提供每个人的认证日期,例如 Machine27? 在 Access 中,我最初拥有

SELECT LastName,FirstName,Forms![F: Reports Switchboard]![Machine Name]  As Expr1
FROM Certifications
WHERE  Forms![F: Reports Switchboard]![Machine Name]>""  

但这提供了一个填充机器名称的列,而不是具有该名称的字段中的日期。

我尝试了许多其他方法包括存储过程:

CREATE PROCEDURE sp_CertDate
    @fieldvar1 varchar(20)
AS      
    SELECT LastName,@fieldvar1
    FROM Certifications
    WHERE  Forms![F: Reports Switchboard]![Machine Name]>""  
GO

但同样,我只是在查询获取字段名称,而不是字段的记录数据。

我想我遗漏了一些明显的东西,但我需要朝着正确的方向努力。任何帮助将不胜感激。

解决方法

由于机器名称是一列表,它是 SQL 语句的结构组件,而不是字符串文字。因此,您需要创建一个动态查询对象,您可以使用 QueryDefs 在 VBA 中处理该对象:

Dim qDef As QueryDef
Dim strSQL As String

strSQL = "SELECT LastName,FirstName,"  _
         &       "[" & Forms![F: Reports Switchboard]![Machine Name] & "] As MachineDate " _
         & "FROM Certifications " _
         & "WHERE [" &  Forms![F: Reports Switchboard]![Machine Name] & "] >'' "

Set qdef = CurrentDb.QueryDefs("mySavedQuery")   ' LOCATE SAVED QUERY
qdef.SQL = strSQL                                ' CHANGE ITS SQL
Set qdef = Nothing                               ' RELEASE OBJECT TO SAVE

但理想情况下,如果您可以避免使用宽格式数据,因为您永远不想在列标题中保存数据元素。正如一位 DBA 大师所说,Why would you need to create a table with even 20 columns,let alone 2000 ???

改为使用更规范化的长表格式并避免复杂查询:

姓氏 名字 机器 日期
堆栈 瑞克 Machine01 5/1/21
堆栈 瑞克 Machine02 5/15/21
堆栈 瑞克 Machine03 5/20/21
... ... ... ...

这样做,不需要 VBA,只需要一个静态 SQL 查询:

SELECT LastName,Machine,[Date]
FROM Certifications
WHERE Machine = Forms![F: Reports Switchboard]![Machine Name]
,

表和字段名称在 Access 查询对象中不能是动态的。

我假设有一个像 EmpID 这样的唯一标识符字段。如果没有,应该有。

可能的选择:

  1. 每个机器字段都具有与 OR 运算符相同的条件 - 50 个字段可能会达到 OR 运算符数量的限制,显然 AND 运算符的数量限制为 99 个

  2. 构建一个 UNION 查询以将机器字段重新排列为规范化结构,并使用该查询作为另一个查询的源进行搜索 - UNION 限制为 50 条 SELECT 行,因此可能几乎无法工作,并且没有构建器或向导对于 UNION,必须在 SQLView 中键入或复制/粘贴

SELECT EmpID,LastName,Machine01 AS CertDate,"Machine01" AS MachineName FROM Certifications
UNION SELECT EmpID,Machine02,"Machine02" FROM Certifications
...;
  1. 在指定机器字段上使用DLookup域聚合函数,字段参数输入参考表单控制
SELECT EmpID,Forms![F: Reports Switchboard]![Machine Name] AS MachineName,DLookup("[" & Forms![F: Reports Switchboard]![Machine Name] & "]","Certifications","EmpID=" & [EmpID]) AS CertDate 
FROM Certifications;
  1. VBA 和 QueryDefs 来修改查询对象