VB6 / SQL“长文本”比较不正确(MS Access 2013)

Posted

技术标签:

【中文标题】VB6 / SQL“长文本”比较不正确(MS Access 2013)【英文标题】:VB6 / SQL "Long Text" not comparing correctly (MS Access 2013) 【发布时间】:2014-01-23 16:12:43 【问题描述】:

我在一个使用 MS Access 2013 的项目上工作了很长时间。我遇到的一个问题是我在表格中有非常长的“评论”,我需要分解并插入到新表格中。每个评论都链接到一个“RouteID”,两者之间的关系可以是多对多的。我遇到的主要问题是我要从中移动数据的表中有重复的 cmets。无需保留重复的“评论”,行中的唯一区别是“RouteID”。基本上我有一个旧 cmets 表和一个新 cmets 表。

我的问题是它没有正确检查我的旧表中的 cmets 是否在新表中并且正在创建重复项。

有些评论被发现是重复的,有些则不是,被发现不重复的 cmets 的大小因大小和符号而异,从短到长不等。

这是我编写的一些代码,我尝试了多个版本的 SQL 和 VBA/VB6 代码,但结果仍然相同,重复的 cmets 出现在我的新表中。无论是否与我的问题有关,请随时批评。

我知道有些查询可能太长而无法工作,所以我做了一个 SQL 查询来比较 TABLE'S,但是这也失败了,并且仍然存在重复的 cmets。我检查了我的代码,我不认为我的逻辑不正确

请帮忙!在我的朋友/教授圈子里似乎没有人知道该怎么做。我有一个想法,把 cmets 和 HASH 放到一个类似的表中,然后用它来检查

If Not (rsOLD.EOF And rsOLD.BOF) Then
    rsOLD.MoveFirst
    Do Until (rsOLD.EOF = True)
        TComment = rsOLD(CommentColumn)
        TResponse = rsOLD(ResponseColumn)
        If Not IsNull(TComment) Then
            TComment = Replace(TComment, "'", "''")
            SQL = "SELECT Comment, ID FROM Comments WHERE Comment = (SELECT '" & CommentColumn & _
                  "' FROM CommentsOld WHERE (CommentsOld.ID = " & rsOLD!ID & "));"
            'SQL = "SELECT Comment FROM Comments" & _
            '      " INNER JOIN CommentsOld" & _
            '      " ON Comments.Comment = CommentsOld." & CommentColumn & _
            '      " WHERE CommentsOld.ID = " & rsOLD!ID & ";"
            Set rsCHECK = CurrentDb.OpenRecordset(SQL, dbOpenDynaset)
            If (rsCHECK.EOF And rsCHECK.BOF) Then 'IF COMMENT DOES NOT EXIST, NOTHING FOUND

我曾尝试使用循环通过记录集的 bool 函数,但考虑到每个表中记录的大小,循环的 BigO 太大,无法在合理的时间内完成。

【问题讨论】:

请仅发布相关代码并缩小代码的实际问题 您是说代码无法识别真正重复但不是精确字符串匹配的 cmets(例如,由于尾随空格、嵌入换行符或类似原因),还是问题所在比这更微妙? 我把代码删减了一些,主要检查在底部。注释的 SQL 代码是我尝试过但无法完成的,因为两者之间的内部连接导致错误,因为这两个表之间的类型不同(从我读到的),但是它们都是相同的。例如,对于重复项,多次插入新表的是“[Forest Service comment]”,我没有看到任何额外/尾随 WS 或换行符。 基本上 rsCHECK.EOF 和 rsCHECK.BOF 总是 True。我还使用了 DLookup() 并检查了它的 VBnullString 以及大于零的长度并得到了相同的结果。 【参考方案1】:

一个可能的原因是您的代码正在执行

SQL = "SELECT Comment, ID FROM Comments WHERE Comment = (SELECT '" & CommentColumn & _
        "' FROM CommentsOld WHERE (CommentsOld.ID = " & rsOLD!ID & "));"

因此,不是返回名称在变量CommentColumn 中的列的内容,而是将列名称作为文字字符串返回。也就是说,如果CommentColumn 包含"Column1" 那么你的SQL 代码没有做

... (Select Column1 FROM CommentsOld ...

它正在做

... (Select 'Column1' FROM CommentsOld ...

也许你应该试试

SQL = "SELECT Comment, ID FROM Comments WHERE Comment = (SELECT [" & CommentColumn & _
        "] FROM CommentsOld WHERE (CommentsOld.ID = " & rsOLD!ID & "));"

编辑回复:评论

由于与文本(短文本)字段相比,备注(长文本)字段存在一些重大限制 w.r.t。连接,DISTINCT 查询(如另一个答案中所述)等。您的散列想法开始看起来越来越有吸引力。在答案here 中有指向各种散列算法的一些 VBA/VB6 实现的链接。

为每条评论生成哈希可能会相当耗时,因此您可能只想执行一次。如果您可以为每个评论列添加一个 [..._hash] 列(例如,为长文本列 [CP1] 添加一个名为 [CP1_hash] 的短文本列)并将哈希存储在其中,那将是理想的。哈希完成后,您可以比较评论 hashes 而不是 cmets 本身。此外,散列列可以以其他有用的方式连接、完全索引和操作。

(是的,哈希冲突的可能性很小,但考虑到您可能正在处理的字符串的长度,我认为这极不可能。)

您肯定想做的一件事是在 WHERE 子句或 JOIN 条件中使用散列函数本身。这将导致表扫描并强制重新计算每一行的所有哈希值,这可能会真正减慢速度。

【讨论】:

使用方括号“运行时错误 '3342': Invalid Memo, OLE, or Hyperlink Object in subquery '[CP1]'”时出现错误(这是列的名称,代表评论期 1)我现在记得这个,我不久前尝试过的东西。类似于我在尝试使用 Inner Join SQL 查询时遇到的错误。 谢谢,我认为那是最好的,我设置了一个散列函数,我希望它可以毫无问题地使用 cmets。更不用说为 cmets Image 设置的可怕桌子了。 我使用Replace(string, "'", "''") 在将评论插入数据库之前为其添加转义字符。我无法决定何时应该在转义字符替换之前或之后获取评论的哈希值。有什么建议么?我相信最终没关系... @JaredTS486 您是否将单引号加倍以准备“粘合在一起”使用单引号作为字符串分隔符的 SQL 语句?如果是这样,那么当文本写入数据库时​​,''s 将被转换回's。换句话说,您没有更改注释文本,您只是对其进行了调整,以便 SQL 语句不会中断。 (但你又知道“粘合在一起”的 SQL 语句是 Bad Idea,对吧...?) 散列 cmets 工作得很好 :) 感谢您的帮助!【参考方案2】:

从一个空表 NewTable 开始。然后运行这个查询:

insert into NewTable (Comment)
SELECT distinct Comment
FROM OldTable;

'distinct' 将排除所有重复项,因此 NewTable 中的结果应该是唯一的。然后,您可以通过 OldTable 对每个 RouteID 做您喜欢的事情。

【讨论】:

在 Access 中,SELECT DISTINCT 和 Memo (Long Text) 字段不能很好地配合使用。在 Access 2010 中,您的语句失败并显示“该字段太小,无法接受您尝试添加的数据量。请尝试插入或粘贴更少的数据。” (如果删除了DISTINCT 关键字,该语句确实可以正常工作。) 嗯。我确实在 Access 2013 中使用长文本字段对其进行了测试(但两个表都是空的)。尽管它没有做任何事情,但它运行良好。 ORDER BY 对 LongText 有什么问题吗? 我在我的新表中看到了相当简单的重复项,例如“[Forest Service comment]”,仅此而已。也许我需要先做一些消毒? 有趣的是,在 Access 2013 中,该语句没有像在 Access 2010 中那样导致错误,但它确实将 [NewTable] 中的值截断为 255 个字符。 (这是 SELECT DISTINCT 对 Access 中的备注字段的一个非常常见的副作用。) 如果 distinct 不起作用,那么您可以选择它们,并带有 ORDER BY Comment。然后在代码中检查每个评论不 = 上一条评论;如果它是重复的并且可以忽略;如果它不是一个新的并被插入到新表中。另一种选择是从 newtable 组中选择评论,count() 通过评论 count() > 1 这将只给你 dups;然后,如果有合理的数量,您可以手动处理它们,如果有很多,则可以使用 vba。

以上是关于VB6 / SQL“长文本”比较不正确(MS Access 2013)的主要内容,如果未能解决你的问题,请参考以下文章

VB6、MS Access、DAO - 显示列名不为空的所有记录

PHP-SQL 不保存长文本

按计数排序未正确排序 - SQL (MS Access 2007)

通过 SQLCMD 将 sql 文件从 MySQL 导入 MS SQL 时语法不正确

有啥方法可以在 DAO 和 MS Access 中使用长文本(备忘录)参数?

VB6 程序连Ora-06413解决手札