2016-07-30 71 views
0

目标:我有一大堆的日期,我想按类别更新最小日期的记录:VBA迭代VS SQL速度在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");

我期待通过每个字典键/值对恩(20165645699,201601) 创建和以各种形式运行此脚本80K +倍

+0

这是SQL做得很好的事情,但我不太明白你想做什么。你想在每个ID的最早的日期有一个“使用”,或者什么? – grahamj42

+0

@ grahmaj42是的,我想在最早的日期使用“Use”,有时最早的日期也会重复多次,所有这些项目都应该标记为使用。我认为这是一个相当清晰的SQL应用程序,但是我的脚本非常慢 - 几个小时,仍然没有完成。 – Schalton

+0

你认为哪些SQL可以“永远占用”? – dbmitch

回答

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 
+0

我很好奇,如果你尝试了我的查询。 – shawnt00

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以避免与保留字发生冲突。]

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

+0

有道理,让我实现,然后我会接受答案 – Schalton

0

我想你可以用一个更新查询 - 或者至少是一个SQL语句中多个查询的组合。

我打算使用您的示例数据,因为我无法确定您的实际表或字段名称在您的评论中。

您需要用您的表名 - 和ID /日期/标记字段替换表4以匹配您的列名称。

UPDATE 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"

等“无标签检查'选项

UPDATE 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); 
+0

我对我的底部查询表 - 800k记录 它已运行了一个小时 – Schalton

+0

你有日期字段上的索引? – dbmitch

+0

它已经运行了大约3:15,进度条是〜20%,这是一个标志,这不是一个可行的解决方案。 不,日期字段尚未编入索引 - 我现在就试一试。 – Schalton

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]  
)