• Privacywetgeving
    Het is bij Helpmij.nl niet toegestaan om persoonsgegevens in een voorbeeld te plaatsen. Alle voorbeelden die persoonsgegevens bevatten zullen zonder opgaaf van reden verwijderd worden. In de vraag zal specifiek vermeld moeten worden dat het om fictieve namen gaat.

Snellere VBA code gezocht voor samenvoegen rijen o.b.v. 2 voorwaarden

Status
Niet open voor verdere reacties.

StiBe

Gebruiker
Lid geworden
23 okt 2016
Berichten
17
In mijn tabel een kolom met datum, kolom met naam en een aantal kolommenn met scores.
Nu kan eenzelfde naam meermaals voorkomen op een bepaalde datum.
Graag wil ik dan deze rijen samenvoegen in één rij, en de scores optellen.

bron
datum naam score
01-01 piet 1
01-01 jan 5
01-01 piet 10
01-01 piet 9
02-01 piet 2
02-01 jan 4
02-01 jan 1

resultaat
01-01 piet 20
01-01 jan 5
02-01 piet 2
02-01 jan 5

Ik heb hiervoor zowel een werkende formule en VBA code.
VBA heeft mijn voorkeur omdat het bestand door anderen gebruikt gaat worden en er per maand ruim 1000 regels bijkomen.
Dit is meteen mijn probleem; het sorteren met mijn VBA code neemt veel tijd in beslag.

Wie o wie kan mij helpen het samenvoegen te versnellen?
Alvast bedankt!

Code:
Public Sub MaaktotaalSQL()
    'sorteren en optellen bij dubbele gebruikersgegevens op dezelfde datum
Dim rs As ADODB.Recordset
Dim cn As ADODB.Connection
Dim vSQLText As String

Set cn = New ADODB.Connection
With cn
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .ConnectionString = "Data Source= " & ActiveWorkbook.Path & "\" & _
        ActiveWorkbook.Name & ";" & _
        "Extended Properties=Excel 8.0;"
    .Open
End With

On Error GoTo Queryfout

vSQLText = "SELECT datum, naam, SUM(score1), SUM(score2), SUM(score3), SUM(totaal) as Waarde FROM [Invoer$] " & _
    "GROUP BY datum, naam;"

Set rs = New ADODB.Recordset
rs.Open vSQLText, cn, adOpenDynamic, adLockReadOnly

rs.MoveLast
rs.MoveFirst
Application.ScreenUpdating = 0

Sheets("Database").Select

Range("B1").Select
Do While Not rs.EOF
    For nTeller = 1 To rs.Fields.Count
        ActiveCell.Offset(0, nTeller - 1) = rs.Fields(nTeller - 1)
    Next
    ActiveCell.Offset(1, 0).Select
    rs.MoveNext
Loop
Dim FirstRow As Long
FirstRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
ActiveSheet.Cells(FirstRow + 1, "A").Value = ActiveSheet.Cells(FirstRow, "A").Value + 1

Set rs = Nothing
Set cn = Nothing

Exit Sub

Queryfout:
Select Case Err.Number
    Case 3021
        If rs.RecordCount = 0 Then
            MsgBox "Gegevens succesvol geladen, totaal " & rs.RecordCount & " records.", vbInformation, "Gelukt"
        Else
            MsgBox "Ongedefinieerde fout", vbInformation, "Fout"
        End If
    Case 3146
        MsgBox "Fout in Query", vbInformation, "Fout"
    Case Else
        MsgBox Err.Description, vbInformation, "Fout"
End Select

End Sub

Voorbeeld met VBA in bijlage:
Bekijk bijlage samenvoegen.xlsm
 
Laatst bewerkt:
Kun je het SQL-statement niet gewoon uitbreiden met "ORDER BY datum, naam"?

Daarnaast zie ik dat je iedere keer een cel selecteerd. Dit werkt vertragend. Probeer dit zoveel mogelijk te voorkomen.
 
Wat is er mis met een draaitabel eigenlijk?
 

Bijlagen

  • samenvoegen JKP.xlsm
    42,5 KB · Weergaven: 41
Dank voor jullie snelle reactie.
Jan Karel; ik voeg aan de resultaten nog extra data toe (deze is wel 1 regel per persoon per datum), kan hiervoor geen gebruik maken van een draaitabel. dit is pas mogelijk als alle gegevens compleet zijn.
Peter: Sorteren is niet zozeer van belang, wel het samenvoegen. ik geloof dat het schrijven veel tijd in beslag neemt, Hoe zou ik dit dan kunnen doen zonder per cel te selecteren?

(Alvast) Dank voor het advies!
 
Is dit sneller?

Resultaat van blad 'invoer' naar database.
Code:
Sub hsv()
Dim sn, sq, i As Long, key
sn = Sheets("invoer").Cells(1).CurrentRegion
With CreateObject("scripting.dictionary")
ReDim arr(2, 0) As String
  For i = 1 To UBound(sn)
   .Item(sn(i, 2) & " " & sn(i, 3)) = .Item(sn(i, 2) & " " & sn(i, 3)) + sn(i, 4) + sn(i, 5) + sn(i, 6)
  Next i
  For Each key In .keys
    sq = Split(key)
     If IsDate(sq(0)) Then
        arr(0, UBound(arr, 2)) = CLng(DateValue(sq(0)))
        Else
         arr(0, UBound(arr, 2)) = sq(0)
         End If
         
        arr(1, UBound(arr, 2)) = sq(1)
        arr(2, UBound(arr, 2)) = .Item(.keys()(UBound(arr, 2)))
    ReDim Preserve arr(2, UBound(arr, 2) + 1)
  Next key
 Sheets("database").Cells(1, 10).Resize(.Count, 3) = Application.Transpose(arr)
End With
End Sub
 

Bijlagen

  • samenvoegen.xlsb
    32,9 KB · Weergaven: 36
Laatst bewerkt:
Deze code is echt razendsnel.
Wel enkele probleempjes met de uitvoer:
- de kolom 'naam' in mijn tabel bestaat uit voor- en achternaam, wordt met uw code niet geheel overgenomen in werkblad 'database', alleen de voornaam
- de scores worden in één kolom bij elkaar opgeteld. ze moeten in afzonderlijke kolommen blijven.

Eigenlijk in het kort: elke gebruiker krijgt per datum 1 rij in 'database'

Ik zal ondertussen even doorpuzzelen, puzzelt u met mij mee? Wederom alvast bedankt!
 
De door mij aangedragen code komt overeen met het door jouw aangeleverd bestandje.
Voor andere oplossingen zijn dus andere gegevens nodig.
 
Dank Harry,

Ik ben inmiddels een stapje verder maar kom niet uit het sorteerverhaal. Jou voorgestelde code heb ik heb ik zodanig mee lopen puzzelen en uitproberen dat deze helemaal niets meer doet :shocked:
Om e.e.a. hopelijk duidelijker te maken een aangepast voorbeeld in bijlage (vereenvoudigde weergave).
In de linker tabel staan namen welke op meer dan één datum kunnen voorkomen.
Als een naam op meerdere data voorkomt wil ik de resultaten van deze data (scores) afzonderlijk samenvoegen.
Elke naam dient dus maximaal één keer per datum voor te komen (zie het gewenste resultaat in de rechter tabel).
Het resultaat dient in werkblad "Database" te verschijnen.

Daarnaast zou het prettig zijn dat na het samenvoegen de gegevens in werkblad "Invoer" gewist worden. Wanneer hier een nieuwe lijst komt moet deze volgens bovenstaande stappen aan werkblad "Database" toegevoegd worden (Dus de gegevens reeds aanwezig in Database worden nooit overschreven).


Uiteindelijk ga ik de verkregen lijst toevoegen aan een andere scorelijst in werkblad "verzameldata" (in de kolommen achteraan) welke de datumkolom en unieke namen al hebben (In deze tabel komen de gebruikers altijd voor, ook als ze geen scores hebben). Misschien dat dit een beter uitgangspunt is?

Wederom dank voor het meedenken!
Bekijk bijlage samenvoegen_test.xlsm
 
Test het maar eens.
Code:
Sub hsv()
Dim sn, sq, i As Long, key, Dic1 As Object, Dic2 As Object, Dic3 As Object
sn = Sheets("invoer").Cells(1).CurrentRegion.Resize(Sheets("invoer").Columns(3).SpecialCells(2).Rows.Count)
With CreateObject("scripting.dictionary")
 Set Dic1 = CreateObject("scripting.dictionary")
 Set Dic2 = CreateObject("scripting.dictionary")
 Set Dic3 = CreateObject("scripting.dictionary")
ReDim arr(5, 0) As String
  For i = 1 To UBound(sn)
  If i = 1 Then
    .Item(sn(i, 2) & "_" & sn(i, 3)) = "Totaal"
    Else
   .Item(sn(i, 2) & "_" & sn(i, 3)) = .Item(sn(i, 2) & "_" & sn(i, 3)) + sn(i, 4) + sn(i, 5) + sn(i, 6)
   End If
   Dic1.Item(sn(i, 2) & "_" & sn(i, 3)) = Dic1.Item(sn(i, 2) & "_" & sn(i, 3)) + sn(i, 4)
    Dic2.Item(sn(i, 2) & "_" & sn(i, 3)) = Dic2.Item(sn(i, 2) & "_" & sn(i, 3)) + sn(i, 5)
     Dic3.Item(sn(i, 2) & "_" & sn(i, 3)) = Dic3.Item(sn(i, 2) & "_" & sn(i, 3)) + sn(i, 6)
  Next i
  For Each key In .keys
    sq = Split(key, "_")
     If IsDate(sq(0)) Then
        arr(0, UBound(arr, 2)) = CLng(CDate(sq(0)))
        Else
         arr(0, UBound(arr, 2)) = sq(0)
         End If
         
        arr(1, UBound(arr, 2)) = sq(1)
        arr(2, UBound(arr, 2)) = Dic1.Item(.keys()(UBound(arr, 2)))
        arr(3, UBound(arr, 2)) = Dic2.Item(.keys()(UBound(arr, 2)))
        arr(4, UBound(arr, 2)) = Dic3.Item(.keys()(UBound(arr, 2)))
        arr(5, UBound(arr, 2)) = .Item(.keys()(UBound(arr, 2)))
    ReDim Preserve arr(5, UBound(arr, 2) + 1)
  Next key
 Sheets("database").Cells(1, 10).Resize(.Count, 6) = Application.Transpose(arr)
End With
End Sub
 

Bijlagen

  • samenvoegen_test.xlsb
    37,3 KB · Weergaven: 40
Die info kan ook worden toegevoegd voordat je de draaitabel maakt, ik zie nog steeds geen voordeel in complexe VBA code tegenover een eenvoudig te onderhouden draaitabel.
 
Volledig met JKP eens:

En als je een ADO-fan bent kan het met 2 regels:

Code:
Sub M_snb()
  With CreateObject("ADODB.Recordset")
    .Open "SELECT datum, naam, SUM(score1), SUM(score2), SUM(score3), SUM(totaal) as Waarde FROM [Invoer$] GROUP BY datum, naam;", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 8.0"""
    Sheets("Pivottable").Cells(20, 1).CopyFromRecordset .DataSource
  End With
End Sub
 

Bijlagen

  • __pivot JKP_snb.xlsx
    32,2 KB · Weergaven: 51
Laatst bewerkt:
Dank voor jullie reactie!

Ik heb beide opties getest, de draaitabel-variant van SNB is bij een grote hoeveelheid data de snelste optie (scheelde bij 2000 regels zo'n 10 seconden) en biedt voor mij bruikbare gegevens.

Nog één vraag: hoe kan ik voorkomen dat bij de geschreven data niet begonnen wordt met een lege regel?

Wederom dank voor jullie inzet!
 
Status
Niet open voor verdere reacties.
Steun Ons

Nieuwste berichten

Terug
Bovenaan Onderaan