VBA - 使用 DAO 对象的运行时错误 3271

Posted

技术标签:

【中文标题】VBA - 使用 DAO 对象的运行时错误 3271【英文标题】:VBA - Run Time Error 3271 using DAO object 【发布时间】:2016-08-31 04:25:00 【问题描述】:

我正在尝试使用DAO.QueryDef 和Microsoft Access 中的本地Append 查询来更新SQL 服务器数据库。我正在更新的一些字段包含很长的字符串(从0700 以上的字符)。

当字符串长度在0255 字符的范围内时,我可以毫无问题地将其传递到我的查询中并更新相应的表。但是,当它们超过 255 字符时,我会收到以下运行时错误:

我一直在使用random string generator website 来创建和测试不同长度的字符串。我还检查了我的数据库中的列数据类型,它们都在NVARCHAR(MAX) 需要的位置。 Microsoft Access 显示相同的相应列,数据类型为 Long text

下面是我的代码 sn-p:

Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef

Set dbs = CurrentDb

If Not IsNull(cmbboxFileNameLogic) Then
    Set qdf = dbs.QueryDefs("qryUpdateFile")

    qdf.Parameters("FileName").Value = txtboxUpdateConversionName.Value
    qdf.Parameters("ZipFileName").Value = txtboxZipFileNameLogic.Value
    qdf.Parameters("OutputFormat").Value = txtboxOutputFormat.Value
    qdf.Parameters("Delimeter").Value = txtboxDelimeter.Value
    qdf.Parameters("DestinationLocation").Value = txtboxDestinationLocation.Value
    qdf.Parameters("DeliveryMechinism").Value = txtboxDeliveryMechinism.Value
    qdf.Parameters("Note").Value = txtboxOutputFileInfoNotes.Value
    qdf.Parameters("Criteria").Value = txtboxOutputFileInfoCriteria.Value
    qdf.Parameters("CustomListKey").Value = txtboxCustomListKey.Value
    qdf.Parameters("ExcludeCustomListKey").Value = txtboxExcludeCustomListKey.Value
    qdf.Parameters("NewspaperFlag").Value = chkNewsPaperFlag.Value
    qdf.Parameters("WebsiteFlag").Value = chkWebsiteFlag.Value
    qdf.Parameters("MarketingFlag").Value = chkProfessionalMarketingFlag.Value
    qdf.Parameters("PrintFlag").Value = chkProfessionalPrintFlag.Value
    qdf.Parameters("WebsiteFlag").Value = chkWebsiteFlag.Value
    qdf.Parameters("BrokerDealerFlag").Value = chkBrokerDealerFlag.Value
    qdf.Parameters("ActiveOnly").Value = chkActiveOnly.Value
    qdf.Parameters("OutputFormatting").Value = txtboxFileFormatting.Value
    qdf.Parameters("Header").Value = txtboxHeader.Value
    qdf.Parameters("Footer").Value = txtboxFooter.Value
    qdf.Parameters("SQLStatement").Value = txtboxSQLStatement.Value
    qdf.Parameters("OrderBy").Value = txtboxOrderBy.Value
    qdf.Parameters("FileID").Value = cmbboxFileNameLogic.Value

    qdf.Execute dbSeeChanges
    qdf.Close

    lblOutputFileInfoAction.Caption = "File successfully updated"
    lblOutputFileInfoAction.Visible = True

Else
    -- Insert new values
End If

查询定义:

UPDATE myTableNameGoesHere SET fldFileNameLogic = [FileName], 
fldZipFileNameLogic = [ZipFileName],fldOutputFormat = [OutputFormat],
fldDelimeter = [Delimeter], 
fldDestinationLocation = [DestinationLocation], fldDeliveryMechinism = [DeliveryMechinism], 
fldNote = [Note], fldCriteria = [Criteria], fldCustomListKey = [CustomListKey],
fldExcludeCustomListKey = [ExcludeCustomListKey], fldNewspaperFlag = [NewspaperFlag], 
fldProfessionalWebsiteFlag = [WebsiteFlag], fldProfessionalMarketingFlag = [MarketingFlag], 
fldProfessionalPrintFlag = [PrintFlag], fldWebsiteFlag = [WebsiteFlag], 
fldBrokerDealerFlag = [BrokerDealerFlag], fldActiveOnly = [ActiveOnly], 
fldFileOutputFormatting = [OutputFormatting], fldHeader = [Header], 
fldFooter = [Footer], fldSQLStatement = [SQLStatement], fldOrderBy = [OrderBy]
WHERE [fldFileID] = [FileID];

【问题讨论】:

假设qryUpdateFile 是一个本地Access 对象,在新查询的SQL 视图中键入带有长文本的普通INSERT 语句是否有效? (不使用 VBA 对象) @Leviathan 是的,这曾经有效。我确实不得不转义某些字符,例如'",这很痛苦。它也对 SQL 注入开放,这就是我选择修改旧代码并使用参数化查询的原因。 qryUpdateFile 是一个本地访问对象,我暂时不调用任何 SQL 存储过程或任何东西。 您能否将qryUpdateFile 的完整SQL(包括PARAMETERS 部分)添加到您的问题中? 嗯,这可能是 DAO 无法正确解释长度超过 255 个字符的文本字段。 qdf.Fields("ProblematicField").Size 返回什么? querydef 将该字段解释为什么类型? (qdf.Fields("ProblematicField").Type) 奇怪......但是,看到 HansUp 的回答,这可能并不重要。如果您不这么认为,我们仍然可以跟进。 【参考方案1】:

您面临 Access SQL 文本参数的限制。它们不能容纳超过 255 个字符的字符串值。

这是一个演示问题的简单示例。

Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strUpdate As String
Dim strLongString As String
strLongString = String(300, "x")
strUpdate = "UPDATE tblFoo SET memo_field = [pLongString] WHERE id=2;"
Set db = CurrentDb
Set qdf = db.CreateQueryDef(vbNullString, strUpdate)
qdf.Parameters("pLongString").Value = strLongString
qdf.Execute dbFailOnError

该代码触发错误 #3271,“无效的属性值。” ...与您看到的相同的错误。

如果我将UPDATE 语句更改为包含这样的PARAMETERS 子句...

strUpdate = "PARAMETERS [pLongString] LongText;" & vbCrLf & _
    "UPDATE tblFoo SET memo_field = [pLongString] WHERE id=2;"

...结果仍然是错误#3271。

我认为没有任何方法可以克服 Access SQL 的限制。

因此,如果您的文本参数值的长度大于 255 个字符,则需要另一种方法。

DAO.Recordset 方法是在字段中存储长文本字符串的简单替代方法。

Dim rs As DAO.Recordset
Dim strSelect
strSelect = "SELECT id, memo_field FROM tblFoo WHERE id=2;"
Set rs = db.OpenRecordset(strSelect)
With rs
    If Not (.BOF And .EOF) Then
        .Edit
        !memo_field.Value = strLongString
        .Update
    End If
    .Close
End With

DAO Reference on MSDN — Recordset object

【讨论】:

我很可能不得不走这条路。谢谢你的详细解释。 哇,这很有趣。让你想知道为什么LongText 是一个有效的参数数据类型。 我也想知道这一点,@Andre。但我仍然看不到LongText 的用处。如果有人能告诉我们,我想会很棒。 :-) 与此同时,至少DAO.Recordset.Edit 有效。 ;-) @Andre 好像是ADO doesn't have this issue.【参考方案2】:

您应该明确定义查询参数,至少是那些具有 LongText 数据类型的参数。否则 Access 必须猜测它们的数据类型。

您可以在查询设计编辑器中执行此操作,单击“参数”按钮。

或者在 SQL 视图中,创建一个PARAMETERS clause

PARAMETERS [parLongString] LongText;
UPDATE myTable
SET LongString = [parLongString]
WHERE ...

【讨论】:

【参考方案3】:

除了HansUp's answer,好像ADO没有这个问题。

添加对 Microsoft ActiveX 数据对象 库的引用(Tools -> References...)(选择最高版本;在我的机器上是 6.1)。

Dim cmd As New ADODB.Command
Set cmd.ActiveConnection = CurrentProject.AccessConnection
cmd.CommandText = "qryUpdateFile"

'the rest of the parameter values need to be included in the array
'omitted for brevity
cmd.Execute , Array(txtboxUpdateConversionName.Value, txtboxZipFileNameLogic.Value)

ADO Reference on MSDN

Command object Command.Execute method

【讨论】:

以上是关于VBA - 使用 DAO 对象的运行时错误 3271的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 SQL 语言中使用 DAO 时 VBA 无法到达第 65,000 行之后的数据?

使用 Excel VBA 创建 Word 应用程序:运行时错误“429”:ActiveX 组件无法创建对象

Excel VBA:运行时错误 424,需要对象

使用 VBA 密码保护进行保存时出现错误消息“运行时错误‘1004’:对象‘_Workbook’的方法‘SaveAs’失败”

删除行时需要 Excel VBA 运行时错误“424”对象

EXCEL的VBA ,连接数据库,运行时错误 424 要求对象