VBA:为什么我的 INSERT 代码不起作用?
VBA: Why is my INSERT code not working?
我几周前就开始工作了,但现在我不确定我做了什么让它不再工作了。我什至没有收到错误消息来弄清楚可能出了什么问题。当我单击我所做的向 table 中插入一行的按钮时,没有任何反应。表单被清除并且 table 被重新查询,但是代码的 INSERT 部分没有做任何事情。
Public Sub Command125_Click()
'Add row for downtime
Dim dbsCurrent As Database
Set dbsCurrent = CurrentDb
dbsCurrent.Execute " INSERT INTO tbl_Downtime " _
& "(job, suffix, production_date, reason, downtime_minutes, comment, shift) VALUES " _
& "('" & Me.Text116 & "','" & Me.Text118 & "','" & Me.Text126 & "','" & Me.Text121 & "','" & Me.Text123 & "','" & Me.Text128 & "','" & Me.Text144 & "');"
Call ClearControl(Me.Text116)
Call ClearControl(Me.Text118)
Call ClearControl(Me.Text126)
Call ClearControl(Me.Text121)
Call ClearControl(Me.Text123)
Call ClearControl(Me.Text128)
Call ClearControl(Me.Text144)
Me.subrpt_DowntimeTable.Requery
End Sub
我根据@Hambone 的回答尝试的代码:
Public Sub Command125_Click()
Dim dbsCurrent As Database
Set dbsCurrent = CurrentDb
Dim query As QueryDef
Dim sql As String
For Each query In CurrentDb.QueryDefs
If query.Name = "InsertDowntime" Then
Exit For
End If
Next query
If query Is Nothing Then
sql = "parameters " & _
"P1 text, P2 text, P3 Date, P4 Text, P5 Number, P6 Text, P7 Text;" & _
"insert into [tbl_Downtime] " & _
"(job, suffix, production_date, reason, downtime_minutes, comment, shift) " & _
" VALUES ([P1], [P2], [P3], [P4], [P5], [P6], [P7])"
Set query = CurrentDb.CreateQueryDef("InsertDowntime", sql)
End If
query.Parameters("P1").Value = "test1"
query.Parameters("P2").Value = "test2"
query.Parameters("P3").Value = Now()
query.Parameters("P4").Value = "test3"
query.Parameters("P5").Value = 15
query.Parameters("P6").Value = "Miles O'Brien is a darn good transporter chief"
query.Parameters("P7").Value = "test6"
query.Execute
MsgBox query.Parameters("P1").Value & query.Parameters("P2").Value & query.Parameters("P3").Value & query.Parameters("P4").Value & query.Parameters("P5").Value & query.Parameters("P6").Value & query.Parameters("P7").Value
Me.subrpt_DowntimeTable.Requery
End Sub
根据我们的讨论,您可能希望查看参数化查询:https://support.microsoft.com/en-us/kb/181734
这样做的主要原因是 1) 它将确保您的代码免受有意或无意的 SQL 注入。由于不能始终在自由格式字段中控制用户输入,因此确保您的查询参数化使得无法执行任意代码; 2) 可读性,当值被参数化时,它使代码更容易阅读。
我不会在执行方法中构建 SQL-语句。
创建一个变量并首先构建字符串。所以可以调试实际值,单独测试。
您也可以尝试执行方法的选项 dbFailOnError
。
Dim stmt as String
stmt = "INSERT INTO....."
dbsCurrent.Execute stmt, dbFailOnError
使用不同的输入测试 INSERT 语句。普通用户将在表单中输入什么并不重要,重要的是应用程序允许他做什么。如果未检查输入并且用户可以输入 he/she 想要的所有内容,那么查询可能会失败,产生奇怪的结果,或者 - 如前所述 - 允许 SQL 注入。最好的 SQL 注入是您作为开发人员永远不会注意到的注入。所以你会知道你有问题。
MarkB 和 gmiley 在使用参数方面完全正确。前面的代码多一点,以后可以节省无数小时。而且,这是一个很好的实践。
也就是说,对于本机 Access 查询(不是 ADO 数据库查询),这不是世界上最直接的过程。在我看来,普通的 ADO 东西在你做了一两次之后就开始有意义了,但是对于 Access 查询,我仍然必须回去抄袭旧的例子才能让它工作。
对于你的情况,我认为这样的事情就可以解决问题:
Dim query As QueryDef
Dim sql As String
For Each query In CurrentDb.QueryDefs
If query.Name = "InsertDowntime" Then
Exit For
End If
Next query
If query Is Nothing Then
sql = "parameters " & _
"P1 text, P2 text, P3 Date, P4 Text, P5 Number, P6 Text, P7 Text;" & _
"insert into [tbl_Downtime] " & _
"(job, suffix, production_date, reason, downtime_minutes, comment, shift) " & _
" VALUES ([P1], [P2], [P3], [P4], [P5], [P6], [P7])"
Set query = CurrentDb.CreateQueryDef("InsertDowntime", sql)
End If
query.Parameters("P1").Value = "test1"
query.Parameters("P2").Value = "test2"
query.Parameters("P3").Value = Now()
query.Parameters("P4").Value = "test3"
query.Parameters("P5").Value = 15
query.Parameters("P6").Value = "Miles O'Brien is a darn good transporter chief"
query.Parameters("P7").Value = "test6"
query.Execute
您正在从文本框中提取数据。我使用硬编码值来证明如果您的值不全是文本,这也可以管理数据类型。无需 'quote' 文本或#hash# 日期。您显然可以将这些更改回 Me.TextBox123
并更改数据类型以匹配 tbl_Downtime
.
中的实际字段
-- 编辑 12/3/15 --
从 For Each query In CurrentDb.QueryDefs
一直到 query.Parameters
的整个代码部分可以 理论上 如果您已经使用此查询文本进行查询,则可以省略在其中(就像您进入 Access,创建查询,从设计视图转到 SQL 视图并输入并命名为 InsertDowntime
):
parameters
P1 text, P2 text, P3 Date, P4 Text, P5 Number, P6 Text, P7 Text;
insert into [tbl_Downtime]
(job, suffix, production_date, reason, downtime_minutes, comment, shift)
VALUES ([P1], [P2], [P3], [P4], [P5], [P6], [P7])
因为你不知道,所以我只是通过代码创建了它。如果您尝试再次创建它,Access 会呕吐,因为 InsertDowntime
已经存在。
无论哪种方式,一旦它存在,您可以通过说
来管理它
Dim query As QueryDef
Set query = CurrentDb.QueryDefs("InsertDowntime")
然后其他一切应该像我拥有的那样。
就我个人而言,我会选择选项 2 -- 在 Access 中创建查询并将其作为持久对象保存并按照我在上面列出的方式访问它。我想我可以这么说,但你的问题是 VBA 左右的问题,我保留了它 VBA -- 另外,我认为动态创建查询的能力有点酷。
我几周前就开始工作了,但现在我不确定我做了什么让它不再工作了。我什至没有收到错误消息来弄清楚可能出了什么问题。当我单击我所做的向 table 中插入一行的按钮时,没有任何反应。表单被清除并且 table 被重新查询,但是代码的 INSERT 部分没有做任何事情。
Public Sub Command125_Click()
'Add row for downtime
Dim dbsCurrent As Database
Set dbsCurrent = CurrentDb
dbsCurrent.Execute " INSERT INTO tbl_Downtime " _
& "(job, suffix, production_date, reason, downtime_minutes, comment, shift) VALUES " _
& "('" & Me.Text116 & "','" & Me.Text118 & "','" & Me.Text126 & "','" & Me.Text121 & "','" & Me.Text123 & "','" & Me.Text128 & "','" & Me.Text144 & "');"
Call ClearControl(Me.Text116)
Call ClearControl(Me.Text118)
Call ClearControl(Me.Text126)
Call ClearControl(Me.Text121)
Call ClearControl(Me.Text123)
Call ClearControl(Me.Text128)
Call ClearControl(Me.Text144)
Me.subrpt_DowntimeTable.Requery
End Sub
我根据@Hambone 的回答尝试的代码:
Public Sub Command125_Click()
Dim dbsCurrent As Database
Set dbsCurrent = CurrentDb
Dim query As QueryDef
Dim sql As String
For Each query In CurrentDb.QueryDefs
If query.Name = "InsertDowntime" Then
Exit For
End If
Next query
If query Is Nothing Then
sql = "parameters " & _
"P1 text, P2 text, P3 Date, P4 Text, P5 Number, P6 Text, P7 Text;" & _
"insert into [tbl_Downtime] " & _
"(job, suffix, production_date, reason, downtime_minutes, comment, shift) " & _
" VALUES ([P1], [P2], [P3], [P4], [P5], [P6], [P7])"
Set query = CurrentDb.CreateQueryDef("InsertDowntime", sql)
End If
query.Parameters("P1").Value = "test1"
query.Parameters("P2").Value = "test2"
query.Parameters("P3").Value = Now()
query.Parameters("P4").Value = "test3"
query.Parameters("P5").Value = 15
query.Parameters("P6").Value = "Miles O'Brien is a darn good transporter chief"
query.Parameters("P7").Value = "test6"
query.Execute
MsgBox query.Parameters("P1").Value & query.Parameters("P2").Value & query.Parameters("P3").Value & query.Parameters("P4").Value & query.Parameters("P5").Value & query.Parameters("P6").Value & query.Parameters("P7").Value
Me.subrpt_DowntimeTable.Requery
End Sub
根据我们的讨论,您可能希望查看参数化查询:https://support.microsoft.com/en-us/kb/181734
这样做的主要原因是 1) 它将确保您的代码免受有意或无意的 SQL 注入。由于不能始终在自由格式字段中控制用户输入,因此确保您的查询参数化使得无法执行任意代码; 2) 可读性,当值被参数化时,它使代码更容易阅读。
我不会在执行方法中构建 SQL-语句。 创建一个变量并首先构建字符串。所以可以调试实际值,单独测试。
您也可以尝试执行方法的选项 dbFailOnError
。
Dim stmt as String
stmt = "INSERT INTO....."
dbsCurrent.Execute stmt, dbFailOnError
使用不同的输入测试 INSERT 语句。普通用户将在表单中输入什么并不重要,重要的是应用程序允许他做什么。如果未检查输入并且用户可以输入 he/she 想要的所有内容,那么查询可能会失败,产生奇怪的结果,或者 - 如前所述 - 允许 SQL 注入。最好的 SQL 注入是您作为开发人员永远不会注意到的注入。所以你会知道你有问题。
MarkB 和 gmiley 在使用参数方面完全正确。前面的代码多一点,以后可以节省无数小时。而且,这是一个很好的实践。
也就是说,对于本机 Access 查询(不是 ADO 数据库查询),这不是世界上最直接的过程。在我看来,普通的 ADO 东西在你做了一两次之后就开始有意义了,但是对于 Access 查询,我仍然必须回去抄袭旧的例子才能让它工作。
对于你的情况,我认为这样的事情就可以解决问题:
Dim query As QueryDef
Dim sql As String
For Each query In CurrentDb.QueryDefs
If query.Name = "InsertDowntime" Then
Exit For
End If
Next query
If query Is Nothing Then
sql = "parameters " & _
"P1 text, P2 text, P3 Date, P4 Text, P5 Number, P6 Text, P7 Text;" & _
"insert into [tbl_Downtime] " & _
"(job, suffix, production_date, reason, downtime_minutes, comment, shift) " & _
" VALUES ([P1], [P2], [P3], [P4], [P5], [P6], [P7])"
Set query = CurrentDb.CreateQueryDef("InsertDowntime", sql)
End If
query.Parameters("P1").Value = "test1"
query.Parameters("P2").Value = "test2"
query.Parameters("P3").Value = Now()
query.Parameters("P4").Value = "test3"
query.Parameters("P5").Value = 15
query.Parameters("P6").Value = "Miles O'Brien is a darn good transporter chief"
query.Parameters("P7").Value = "test6"
query.Execute
您正在从文本框中提取数据。我使用硬编码值来证明如果您的值不全是文本,这也可以管理数据类型。无需 'quote' 文本或#hash# 日期。您显然可以将这些更改回 Me.TextBox123
并更改数据类型以匹配 tbl_Downtime
.
-- 编辑 12/3/15 --
从 For Each query In CurrentDb.QueryDefs
一直到 query.Parameters
的整个代码部分可以 理论上 如果您已经使用此查询文本进行查询,则可以省略在其中(就像您进入 Access,创建查询,从设计视图转到 SQL 视图并输入并命名为 InsertDowntime
):
parameters
P1 text, P2 text, P3 Date, P4 Text, P5 Number, P6 Text, P7 Text;
insert into [tbl_Downtime]
(job, suffix, production_date, reason, downtime_minutes, comment, shift)
VALUES ([P1], [P2], [P3], [P4], [P5], [P6], [P7])
因为你不知道,所以我只是通过代码创建了它。如果您尝试再次创建它,Access 会呕吐,因为 InsertDowntime
已经存在。
无论哪种方式,一旦它存在,您可以通过说
来管理它Dim query As QueryDef
Set query = CurrentDb.QueryDefs("InsertDowntime")
然后其他一切应该像我拥有的那样。
就我个人而言,我会选择选项 2 -- 在 Access 中创建查询并将其作为持久对象保存并按照我在上面列出的方式访问它。我想我可以这么说,但你的问题是 VBA 左右的问题,我保留了它 VBA -- 另外,我认为动态创建查询的能力有点酷。