2016-07-30 60 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]  
)