2014-02-13 65 views
4

我將數據有問題地插入表中。當我從另一張桌子上做到這一點時,它很快捷,如果有很多記錄,只會略微減慢。即便如此,這只是幾秒鐘的事情。將查詢中的數據插入到表中時,插入的每個記錄是否都運行查詢?

當我從查詢插入表時,它進入分鐘 - 每插入一千條記錄大約一分鐘。

源查詢本身在作爲select查詢運行時,可能需要1-2秒。查詢是否爲每個插入的記錄運行?我希望它能爲整個數據集運行一次。或者,與插入另一個表中的「平坦」數據相比,導致該功能運行速度非常慢的其他因素。

我使用的VBA是相當無害:

CurrentDb.Execute "SELECT [Extra Value Concatenation].* _ 
INTO [" & strTableName & "] FROM [Extra Value Concatenation];" 

和源查詢低於 - 它使用Allen Browne's Concatenate function

SELECT [Extra Fields - Fee Protection Insurance Concatenate].ContactID, 
ConcatRelated('[Fee Protection Insurance]', 
'[Extra Fields - Fee Protection Insurance Concatenate]', 
'ContactID = ' & [ContactID]) 
AS [Fee Protection Insurance] 
FROM [Extra Fields - Fee Protection Insurance Concatenate]; 

編輯:在回答Fionnuala的評論,但我無法正確地在評論中格式化。

使用虛構數據,這裏大概是我想要的。

T1包含客戶記錄。

ContactID Name 
1   Example Limited 
2   Another Company Limited 

T2包含額外的字段。 ContactID作爲外鍵存在,並且如果存在多個記錄,則可以重複。

ContactID FieldValue 
1   Value 1 
1   Value 2 
2   Value 3 
2   Value 4 
2   Value 5 

當我離開聯接表,從T2的重複出現,所以我得到

ContactID Name      FieldValue 
1   Example Limited   Value 1 
1   Example Limited   Value 2 
2   Another Company Limited Value 3 
2   Another Company Limited Value 4 
2   Another Company Limited Value 5 

當我要的是

ContactID Name      FieldValue 
1   Example Limited   Value 1; Value 2 
2   Another Company Limited Value 3; Value 4; Value 5 

因此串聯在一個臨時的數據表似乎是一個好主意,但是會放慢一切。有另外一種方法我應該查看我的查詢嗎?

+2

您使用用戶定義函數(UDF)ConcatRelated,所以UDF運行的每個記錄,否則,通常不會。 – Fionnuala

+0

謝謝@Remou - 是的,我是,這是Concatenate位。有沒有辦法解決? – BFWebAdmin

+2

除了避免UDFs,如果你需要速度,不,沒有辦法解決。爲什麼你想連接?這幾乎總是一個壞主意。 – Fionnuala

回答

2

您正在使用用戶定義的函數(UDF)ConcatRelated,因此UDF將針對每條記錄運行,否則通常Access SQL將以正常方式運行。

4

我寫了一個非常基本的模塊,與您當前的過程相比,您應該很快就能完成此任務。請注意,您需要將項目重命名爲項目導航窗格上的「數據庫」之外的其他項目才能生效

我假定table1和table2與上面的相同 table3只是一個列表在表1中的所有記錄與一個空白「FieldValues」字段添加 所需的「值1,值」等等。這將導致在表3被填入你想要的結果

項重要的:對於使用記錄.edit和任何人。更新功能確保您刪除訪問選項菜單中的記錄級別鎖定,可以在Access選項的「客戶端設置」部分下找到它,否則會導致文件極度膨脹,因爲訪問不會丟失記錄鎖只是你壓縮並修復數據庫。這可能會導致您的數據庫一旦達到Windows的2GB限制就無法恢復。在pegicity的回答

Function addValueField() 

'Declarations 
Dim db As Database 
Dim rs1 As DAO.Recordset 
Dim rs2 As DAO.Recordset 
Dim qry As String 
Dim value As String 
Dim recordcount as Long 


Set db = CurrentDb() 

'Open a select query that is a join of table 1 and table 2 
'I have made Contact ID a foreign key in the second table 
qry = "SELECT Table1.[Contact ID], Table1.Name, Table2.FieldValue FROM Table1 INNER  JOIN Table2 ON Table1.[Contact ID] = Table2.[Contact ID(FK)] ORDER BY [Contact ID];" 

Set rs1 = db.OpenRecordset(qry, dbOpenDynaset) 


'Table 3 was filled with each record from table1, with a 3rd "Field Value" field to 
'be filled with your Value 1, Value 2 etc. 
qry = "SELECT * FROM Table3 ORDER BY [Contact ID]" 

Set rs2 = db.OpenRecordset(qry, dbOpenDynaset) 

'Ensure you have enough file locks to process records 
recordcount = rs1.recordcount 
DAO.DBEngine.SetOption DAO.dbMaxLocksPerFile, recordcount + 1000 

rs1.MoveFirst 
rs2.MoveFirst 

'Here we test to see if "Name" is the same in both recordsets, if it is, add the  FieldValue 
'to the FieldValue in Table3, otherwise move to the next record in table 3 and compare again 


Do While Not rs1.EOF 
    If IsNull(rs2![FieldValue]) = True Then 
     If rs2![FieldValue] = "" Then 
      rs2.Edit 
      rs2![FieldValue] = rs1![FieldValue] 
      rs2.Update 
      rs1.MoveNext 
     Else 
      rs2.Edit 
      rs2![FieldValue] = rs2![FieldValue] & "; " & rs1![FieldValue] 
      rs2.Update 
      rs1.MoveNext 
     End If 
    Else 
     rs2.MoveNext 
    End If 
    Loop 
rs1.close 
rs2.close 
db.close 
set db = nothing 
set rs1 = nothing 
set rs2 = nothing 

End Function 
+0

對不起,但我必須downvote這一個。對目標記錄集進行重複的「.Edit」和「.Update」操作會使數據庫膨脹很多。當我在我的百萬行測試表(48MB)上試用它時,你的例程將.accdb文件分解爲2GB,並使數據庫無法使用。相比之下,ConcatRelated()make-table方法只需一分鐘即可完成,但數據庫僅從48MB增加到90MB左右。由於ConcatRelated()足夠大的數據量顯着影響性能,因此這不是一個非常好的解決方法。 :( –

+0

@GordThompson我有點困惑,爲什麼你會遇到這麼多的記錄膨脹......我經常處理沒有這個大小的表格,然後我想起你需要禁​​用記錄級鎖定以確保訪問doesen't商店所有的記錄鎖定在內存中,這也將大大減少處理時間,在訪問的「客戶端設置」下取消選中「使用記錄級鎖定打開數據庫」選項,你應該可以毫無問題地運行它,如果你願意 – pegicity

+0

是的,取消選中「使用記錄級鎖定打開數據庫」避免了這個問題,並且該方法證明比ConcatRelated()生成表方法快得多。請編輯您的答案以添加配置調整,然後我將刪除我的downvote(調整的確很重要,因爲一旦數據庫文件遇到2GB的「牆」,它可能很難恢復。) –

1

大廈,我最終的代碼爲:

Option Compare Database 

Sub Concatenate(strTableToConcatenate As String, strFieldToConcatenate As String, strIDField As String) 

Dim rsSource As DAO.Recordset 
Dim rsDestination As DAO.Recordset 
Dim qry As String 
Dim strSourceTable As String 
Dim i As Integer 
Dim strFieldName As String 
Dim strValue As String 
Dim intConcatenateID As Integer 
Dim intSortID As Integer 

strSourceTable = strTableToConcatenate & " (Concatenate)" 'Creates a duplicate copy of the table to be concatenated and empties the original table' 
DeleteTable (strSourceTable) 
DoCmd.CopyObject , strSourceTable, acTable, strTableToConcatenate 
qry = "DELETE FROM [" & strTableToConcatenate & "]" 
CurrentDb.Execute (qry) 

qry = "ALTER TABLE [" & strTableToConcatenate & "] ALTER COLUMN [" & strFieldToConcatenate & "] memo" 'Changes the DataType of the field to be concatenated to Memo, as the result may be considerably longer than the original data' 
CurrentDb.Execute (qry) 

i = 0 
intCurrentID = 0 

qry = "SELECT * FROM [" & strSourceTable & "] ORDER BY [" & strIDField & "], [" & strFieldToConcatenate & "]" 
Set rsSource = CurrentDb.OpenRecordset(qry, dbOpenDynaset) 
qry = "SELECT * FROM [" & strTableToConcatenate & "]" 
Set rsDestination = CurrentDb.OpenRecordset(qry, dbOpenDynaset) 

For Each fld In rsSource.Fields 'Finds the column number of the fields you are sorting by and concatenating from your source table.' 
    strFieldName = rsSource.Fields(i).Name 
    If strFieldName = strFieldToConcatenate Then 
     intConcatenateID = i 
    ElseIf strFieldName = strIDField Then 
     intSortID = i 
    End If 
    i = i + 1 
Next 

If rsSource.recordcount <> 0 Then 

    rsSource.MoveFirst 
    intCurrentID = rsSource.Fields(intSortID).Value 
    strConcatenateValue = "" 

    While Not rsSource.EOF 'The source recordset is sorted by your designated sort field, so any duplicates of that field will be next to each other. If the row below has the same id as the row above, the sub continues to build the concatenated value. If the row changes, it adds the concatenated value to the destination record set.' 

     If intCurrentID = rsSource.Fields(intSortID).Value Then 

      strConcatenateValue = strConcatenateValue & "," & rsSource.Fields(intConcatenateID).Value 
      rsSource.MoveNext 

     Else 
      rsDestination.AddNew 

      i = 0 

      If Len(strConcatenateValue) > 0 Then 
       strConcatenateValue = Right(strConcatenateValue, Len(strConcatenateValue) - 1) 
      End If 

      For Each fld In rsSource.Fields 
       strFieldName = rsSource.Fields(i).Name 
       If strFieldName = strFieldToConcatenate Then 
        strValue = strConcatenateValue 
       ElseIf strFieldName = strIDField Then 
        strValue = intCurrentID 
       Else 
        strValue = rsSource.Fields(i).Value 
       End If 
       rsDestination.Fields(strFieldName) = "" & strValue & "" 
       i = i + 1 
      Next 

      rsDestination.Update 
      intCurrentID = rsSource.Fields(intSortID).Value 
      strConcatenateValue = "" 

     End If 

    Wend 

End If 

rsSource.Close 
rsDestination.Close 
Set rsSource = Nothing 
Set rsDestination = Nothing 

End Sub