访问中的VBA迭代与SQL速度

时间:2016-07-30 16:25:31

标签: sql access-vba sql-update access

目标:我有一堆日期,我想按类别更新最短日期的记录:

JVID    APDATE      TAG     into >      JVID    APDATE      TAG
1       201501      Use                 1       201501      Don't Use
1       201502      Use                 1       201502      Use
1       201502      Use                 1       201502      Use
1       201503      Use                 1       201503      Use
2       201502      Use                 2       201502      Don't Use
2       201503      Use                 2       201503      Use

我使用的方法如下: 我创建了一个字典,其中Key = ID,Value = MinDateByID 然后我循环遍历键(对于字典中的每个键),并为检查IIF语句更新的每个ID运行更新查询。使用/不要根据与最小日期匹配的日期使用。

这样做有效,但w / + 80k ID覆盖了+ 1M记录,它需要永远。

我考虑运行相同的东西,但是倾销SQL并且只是遍历记录,但我无法想象会更快?

我正在寻找SQL或VBA建议。

提前谢谢!

编辑 - 从评论添加SQL UPDATE [FY16 Q12 BE] SET [FY16 Q12 BE].[Record Use] = IIF([FY16 Q12 BE].[Date] = "201601", "Use", "Don't Use") WHERE ([FY16 Q12 BE].[ID]="20165645699");

  

我浏览每个字典键/值对ex(20165645699,201601)   以80k +次的各种形式创建和运行此脚本

4 个答案:

答案 0 :(得分:1)

MS Access在联接更新中比主流数据库更具限制性,因此我不得不使用临时表T2来保存最小值。

SELECT T1.ID, MIN(T1.RDate) AS MinDate INTO T2 FROM Test1 GROUP BY T1.ID;

现在我可以执行联接更新:

UPDATE T1 LEFT JOIN T2 ON T1.ID=T2.ID AND T1.RDate=T2.MinDate;

最后,我删除临时表:

DROP T2; SET TAG = IIF(T2.ID IS NULL, "Don't Use", "Use");

[我已将您的表格T1命名为日期字段RDate,以避免与保留字词发生冲突。]

这可以通过在T2上添加主键(ID,MinDate)和在T1上添加索引(ID,RDate)来进一步加速。

答案 1 :(得分:0)

我认为您可以使用一个更新查询来执行此操作 - 或者至少在一个SQL语句中使用多个查询的组合。

我将使用您的示例数据,因为我无法弄清楚您的评论中您的实际表格或字段名称。

您需要将Table4替换为您的表名 - 以及ID /日期/标记字段以匹配您的列名。

更新SQL:

UPDATE Table4 SET Table4.Tag = "Don't Use"
WHERE ([Date] & "-" & [ID]) 
In (SELECT MergeID FROM 
    (SELECT Mins.[MinOfDate] & "-" & [ID] AS MergeID
        FROM 
        (SELECT Table4.ID, Min(Table4.Date) AS MinOfDate
            FROM Table4
            WHERE Table4.Tag="Use"
            GROUP BY Table4.ID) AS Mins) AS Merges);

如果您不需要标准来检查尚未更改的标签,那么您可以取消标准WHERE Table4.Tag="Use"

其他'无标签检查' OPTION

更新SQL:

UPDATE Table4 SET Table4.Tag = "Don't Use"
WHERE ([Date] & "-" & [ID]) 
In (SELECT MergeID FROM 
    (SELECT Mins.[MinOfDate] & "-" & [ID] AS MergeID
        FROM 
        (SELECT Table4.ID, Min(Table4.Date) AS MinOfDate
            FROM Table4
            GROUP BY Table4.ID) AS Mins) AS Merges);

答案 2 :(得分:0)

我想建议一下。但我发现你有重复的日期,我不确定你是否打算在最早的约会时有这些处理。

update [FY16 Q12 BE]
set TAG = "Don't use"
where not exists (
    select 1 from [FY16 Q12 BE] as t2
    where t2.ID = [FY16 Q12 BE].ID and t2.[DATE] < [FY16 Q12 BE].[DATE]       
)

答案 3 :(得分:0)

我选择了迭代方法 - 我不确定为什么它比上面的SQL选项大纲要快得多,但它确实可以解决问题。感谢您的反馈。

Sub MinAPInclude(ByVal Tablename As String)
Dim db As DAO.Database
Dim qd As DAO.QueryDef
Dim rs As DAO.Recordset
Dim strList As String
Dim JVMinAP As Dictionary
Set JVMinAP = New Dictionary
Set db = DBEngine(0)(0)
Dim rst As DAO.Recordset

If Not DoesFieldExist(Tablename, "APDate") Then Exit Sub
SQLStatement = "SELECT [" & Tablename & "].[JVID], Min([" & Tablename & "].[APDate]) AS TargetAP"
SQLStatement = SQLStatement & " FROM [" & Tablename & "]"
SQLStatement = SQLStatement & " GROUP BY [" & Tablename & "].[JVID];"

Set qd = db.CreateQueryDef("", SQLStatement)
Set rs = qd.OpenRecordset

rs.MoveFirst
Do Until rs.EOF
    If Not IsNull(rs("JVID")) Then
        If Not JVMinAP.Exists(CStr(rs("JVID"))) Then
            MinAP = rs("TargetAP")
            JVMinAP.Add CStr(rs("JVID")), MinAP
        End If
    End If
    rs.MoveNext
Loop
rs.Close

Set rst = db.OpenRecordset(Tablename)
rst.MoveFirst
Do Until rst.EOF
    If rst("Record Use") <> "Include" Then
        If rst("APDate") = JVMinAP(CStr(rst("JVID"))) Then
            rst.Edit
                rst("Record Use") = "Include"
            rst.Update
        End If
    End If
rst.MoveNext
Loop

rst.Close
Set rst = nothing
Set rs = Nothing
Set qd = Nothing
Set db = Nothing
End Sub