2014-02-13 59 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