在VBA中使用MS Access的SELECT INTO

3
我遇到了应用程序功能的一些问题。特别是在管理员审查表单上有一个“待定类”的实例时。该表单中填充了与这个待定类相关联的学生。完成他们的成绩后,我在页脚上有一个按钮,它将从我的“待定”表中删除此类,并将所有学生的成绩加入。这起作用了。 但是,在待处理类被删除之前,我想要将其复制到已完成的课程表中,其中只包含班级名称、日期和教师。由于除主键(班级编号)外,在该表单中没有关于该类的任何数据,因此我无法将行的其他字段(班级名称、日期)添加到我的已完成的课程表中。 我正在尝试使用VBA中的“SELECT INTO”操作来获取这些值。具体方法如下:
   dim cname as String
   dim classdate as Date
   dim pid as integer
   dim teacher as String
   dim qry as String

    pid = [Forms]![frmClasses]![txtID]

   qry = "Select className INTO cname FROM tblPending WHERE tblPending.id = " & " ' " & pid & " ' " & ";"

   db.execute qry
   debug.print qry
   debug.print cname   

从这里开始,我对每个其他变量执行相同的操作,构建我的INSERT查询,然后执行它。问题是-我的SELECT INTO语句不起作用。Debug.print显示本地变量从SELECT INTO语句中从未初始化。有什么想法吗?


那是一个制作表查询,我想你想要一个追加查询。我真的不认为你的ID是文本。如果pid为空,则[Forms]![frmClasses]![txtID]也很可能为空。尝试使用Me关键字并查看它出现了哪些控件名称--Me.将带来智能感知。 - Fionnuala
如果我通过 qry = "SELECT ClassName INTO " & cName & " WHERE tblPending.ID = " & "'" & pid & "'" & ";" 来构建查询,那么它就是 "SELECT ClassName INTO cName FROM tblPending WHERE tblPending.id = '17';"。 - Scotch
我现在通过添加隐藏控件来保存值来解决了这个问题,但如果有人知道如何使用SELECT INTO执行此操作,我仍然想知道。 - Scotch
2
SELECT INTO 会创建一个新表,你需要的是 INSERT INTO,它会将数据追加到现有表中。此外,添加 db.execute qry, dbFailOnerror - 如果表已存在,你的查询将失败,否则你将不会收到警告。 - Fionnuala
1
在MS Access中,您可以使用DLookup()来“将选择结果存储到变量中”http://office.microsoft.com/en-us/access-help/dlookup-function-HA001228825.aspx 您可能会发现其他“域函数”也很有用:DMin(); DMax(); DAvg(); 等等。 - HansUp
显示剩余6条评论
2个回答

3
首先,将所有课程放在一个表中,并只设置一个“未完成”或“已完成”列会更好。将两个完全相同的表用于课程,并将值从一个表移到另一个表以指示状态更改是不良的数据库设计。
如果您确实需要使用两个表格复制行来完成此操作,请按照评论中 Remou 已经提到的方式使用 一个 INSERT INTO 查询 (而不是SELECT INTO),因为SELECT INTO会创建一个新表(或覆盖同名的现有表,如果已经存在)。 INSERT INTO 的语法如下:
INSERT INTO CompletedClassTable (ClassName, Teacher)
SELECT ClassName, Teacher FROM tblPending WHERE id = 123

最后,您在评论中提出了以下问题:
“在Access和Oracle中,SELECT INTO是完全不同的吗?在Oracle和PL/SQL中,您可以将一行选择到变量或表中。在Access中,您不能选择到变量中吗?”
要将一行加载到变量中,您需要使用 Recordset
以下是将查询加载到Recordset并输出ClassName字段的示例代码:
Dim RS As DAO.Recordset

Set RS = CurrentDb.OpenRecordset("SELECT * FROM tblPending WHERE id = 123")
If Not RS.EOF Then
    Debug.Print RS("classname")
End If
RS.Close
Set RS = Nothing

我觉得我的“select into”语句的预期用途被误解了。我的意图是从一个已知主键的表中使用SELECT INTO获取一行的值,并将其分配给VBA中的变量,就像在PL/SQL中一样。如你所提到的,遍历RS似乎是Access的比较解决方案。就数据库设计而言,待处理表和完成表并不完全相同。在这种情况下,我认为已完成的课程和正在进行的课程(待处理)是不同的实体。 - Scotch
我不确定我的问题是否含糊不清或者我的意图不明确,但是我会将其标记为“已回答”——在VBA中无法使用“SELECT INTO”将行的值分配给变量。要实现这一点,我需要打开所需查询的记录集。在您看来,这是一个合适的总结吗? - Scotch
1
我不了解Oracle和PL/SQL,所以除了你说的内容外,我无法描述它们的工作原理。要将行中的值分配给变量,您需要一个Recordset或者,如果您仅需要一个值,可以使用 DLookup。但是,如果您只想将一行复制到另一个表中,我建议使用INSERT INTO查询。在我看来,这是最简单的方法。 - Christian Specht
好的,谢谢您的建议。我会接受并视为已回答。 - Scotch

1

看起来你想从tblPending中检索一个文本值className,其中tblPending.id匹配在你的文本框txtID中找到的值,并将该文本值存储在一个名为cname的字符串变量中。

如果这个解释是正确的,那么你不需要使用查询和记录集。只需使用DLookup函数检索值,类似于这个未经测试的代码示例。

Dim cname As String
Dim pid As Integer
Dim strCriteria As String
pid = [Forms]![frmClasses]![txtID]
strCriteria = "id = " & pid
cname = Nz(DLookup("className", "tblPending", strCriteria), vbNullString)
Debug.Print "cname: '" & cname & "'"

注意事项:

  1. 我假设 tblPending 表中的 id 字段数据类型为数字。如果实际上是文本数据类型,请像这样更改 strCriteria

    strCriteria = "id = '" & pid & "'"

  2. DLookup() 如果没有找到匹配项,则返回 Null。由于我们将函数的返回值分配给字符串变量,因此我使用了 Nz() 将 Null 转换为空字符串。或者,您可以声明 cname 为 Variant(以便它可以接受 Null 值),并且摆脱 Nz()


这也可以。在你回答我的问题后,我使用dLookup实现了我的表单,并且它有效(我的代码类似于你提供的答案中的代码)。以前,我使用前一个表单上的隐藏控件来存储变量——这是一个丑陋的解决方法,因为我不知道DLookup()。感谢让我意识到它,我相信将来我会经常使用它,因为我更喜欢使用VBA编写插入、更新和删除操作,而不是使用向导提供的默认操作。 - Scotch
1
一旦我意识到你真正想要将SELECT INTO 一个变量DLookup()成为了简单的解决方案。当我第一次阅读你的问题时,我误解了目标,认为是将SELECTed值存储在表格(新的或现有的)中。 - HansUp
我认为Remou和Christian也是这样想的。我习惯使用SELECT INTO在PL/SQL中将表中的值获取到本地变量中。这就是混淆的根源所在。我不想使用'SELECT INTO',我想知道Access中相应操作的等效方法是什么。DLookup就是我一直在寻找的答案。 - Scotch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接