Excel VBA: Untuk Setiap pengaturan loop

Sunting: Menambahkan contoh data mentah di bawah

Saya menjalankan laporan klaim setiap bulan dan menyalin data ke dalam tab. Semua data disusun dalam kolom dan saya telah menggunakan spreadsheet yang penuh dengan SumProduct dan CountIf untuk menghitung dan mengatur data berdasarkan kumpulan kriteria yang berbeda tetapi prosesnya terlalu lama, jadi saya mencoba menulis VBA sub untuk mencapai hal ini dengan lebih efisien. Salah satu kolom datanya adalah "Adjuster Home Office". Kolom ini pada dasarnya adalah daftar kantor asal setiap klaim. Saya menggunakan AdvancedFilter untuk mengekstrak semua nilai unik di kolom ini dan menyalinnya ke tab terpisah di kolom A. Kemudian, di kolom C, di bawah setiap lokasi, saya memiliki daftar jenis klaim atau "item baris" yang ditangani di masing-masing lokasi. kantor. Saya tidak punya masalah dalam menyiapkan bagian ini. Di kolom D, saya harus bisa menampilkan jumlah setiap item baris di lokasi yang ditentukan. Di sinilah semua Countif dan SumProduct berperan dalam template lama yang saya gunakan. Di sinilah saya menemui hambatan. Saya mencoba menggunakan loop For Each untuk menghitung setiap item baris di kolom B di bawah lokasi pertama, lalu pindah ke lokasi berikutnya di kolom A dan ulangi. Di bawah ini adalah kode yang saya coba:

Private Sub CommandButton23_Click()

Dim linerngs As Range
Dim lineitem As Range
Dim lastlinerow As Long
Dim wsf
Dim TabLastRow
Dim claimstab As String
Dim officesrange As Range
Dim office As Range

claimstab = Sheet2.Range("F2") & " Claims"

TabLastRow = Sheets(claimstab).Cells(Sheets(claimstab).Rows.Count, "A").End(xlUp).Row

Set wsf = Application.WorksheetFunction

officeslastrow = Sheet2.Range("A" & Rows.Count).End(xlUp).Row
lastlinerow = Sheet2.Range("C" & Rows.Count).End(xlUp).Row

Set officerng = Range("A6:A" & officeslastrow).SpecialCells(xlCellTypeConstants, 23)
Set linerngs = Range("C7:C" & lastlinerow).SpecialCells(xlCellTypeConstants, 23)

For Each office In officerng
    For Each lineitem In linerngs
        If InStr(1, lineitem.Value, "IN") > 0 And InStr(1, lineitem.Value, "AOS") = 0 Then
            lineitem.Offset(0, 3) = Application.WorksheetFunction.SumProduct(wsf.CountIfs(Sheets(claimstab).Range("B2:B" & TabLastRow), office))
        End If
    Next lineitem
Next office


End Sub

Saya tahu ini salah karena loop ini akan mengulang semua yang ada di kolom B, bukan hanya item baris di bawah setiap lokasi. Jadi yang saya dapatkan adalah hitungan lokasi terakhir yang ditampilkan untuk setiap item baris di seluruh kolom. di bawah ini adalah contoh tampilan yang saya perlukan. Saat ini, yang saya pedulikan hanyalah menyiapkan loop agar berjalan dengan benar.

contoh dari apa yang saya dapatkan saat ini [contoh dari apa yang saya dapatkan saat ini

contoh dari apa yang saya coba dapatkan [contoh dari apa yang saya coba dapatkan

Anda dapat melihat dari contoh pertama bahwa saya mendapatkan nilai "3" untuk semuanya. Saya menyertakan poros lokasi dan nilainya. Anda dapat melihat bahwa lokasi terakhir di pivot, South Portland, memiliki hitungan 3.

Bantuan apa pun akan SANGAT dihargai.

contoh data mentah [contoh data mentah

Tujuan [objective

[Sumber Item Barisdaftar item baris selesai dibuat oleh formulir pengguna yang meminta masukan pengguna


person Graham Chandler    schedule 23.11.2015    source sumber
comment
Catatan singkat saat menggunakan beberapa sheet, selalu nyatakan secara eksplisit sheet mana yang Anda gunakan, saat menggunakan Cells(), Range(), Rows.Count, dll. Misalnya, ubah baris Anda menjadi officeslastrow = Sheet2.Range("A" & Sheet2.Rows.Count).End(xlUp).Row (dan hal yang sama untuk variabel lain).   -  person BruceWayne    schedule 24.11.2015
comment
Atlanta, GA seharusnya 7?   -  person findwindow    schedule 24.11.2015
comment
ya @findwindow, saya membuat kesalahan di sana. Atlanta, GA seharusnya berusia 7 tahun   -  person Graham Chandler    schedule 24.11.2015
comment
pastinya ini tidak akan lebih cepat daripada rumus yang menggunakan VBA yang mengulang rentang. Ini mungkin tidak akan lebih cepat menggunakan VBA yang dioptimalkan (misalnya loop over varian array). Akan lebih baik jika Anda meminta bantuan untuk mengoptimalkan formula Anda pada awalnya.   -  person chris neilsen    schedule 24.11.2015
comment
@BruceWayne terima kasih, saya akan mengingatnya   -  person Graham Chandler    schedule 24.11.2015
comment
@chrisneilsen sejauh ini, ini sangat cepat dibandingkan dengan templat rumus yang saya gunakan.   -  person Graham Chandler    schedule 24.11.2015
comment
Maksud saya adalah jika rumus Anda sangat lambat, Anda mungkin salah melakukannya. Mereka juga harus cepat. Dan jika Anda tetap menggunakan VBA, silakan lihat array varian, yang besarnya lebih cepat daripada rentang perulangan   -  person chris neilsen    schedule 24.11.2015
comment
@chrisneilsen Saya juga mencoba menjaga ini dari kesalahan pengguna. rekan kerja saya adalah pengguna excel tingkat pemula.   -  person Graham Chandler    schedule 24.11.2015
comment
bantuan apa pun dalam hal ini akan sangat luar biasa. jika saya bisa menyelesaikannya, pada dasarnya saya bisa menyelesaikan keseluruhan proyek   -  person Graham Chandler    schedule 24.11.2015


Jawaban (1)


Ini mungkin bukan jawaban yang Anda cari, tapi menurut saya inilah cara saya mendekati proyek Anda. Akan sangat membantu jika Anda melihat data mentah yang Anda dapatkan di laporan dan menempelkannya ke dalam spreadsheet.

Dua asumsi pertama (dan Anda tahu apa yang mereka katakan tentang asumsi)

  1. Data diambil dari database dan dikembalikan sebagai baris yang mungkin tidak berurutan. Misalnya:

 ATLANTA, GA     IN-AK, HI  3  IN-CA  2  ...  IncidentOnly  4
 BOCA RATON, FL  IN-AK, HI  3  IN-CA  6  ...  IncidentOnly  5 
 ATLANTA, GA     IN-AK, HI  1  IN-CA  0  ...  IncidentOnly  2 
 ...
 AURORA, IL      IN-AK, HI  7  IN-CA  3  ...  IncidentOnly  4 
  1. Anda ingin semua produk asuransi dijumlahkan untuk setiap kantor dan kemudian ditampilkan dalam format laporan yang lebih cantik.

If these assumptions are true (or close to true), you could create a HomeOffice class that had a property for each type of insurance, then simply loop through the rows of data in the raw report and add each HomeOffice object to a collection so you get a unique list of offices.

Contoh dari proyek serupa yang saya lakukan:

Raw Data:
Mary    2   6
Sally   4   9
Mary    4   1
Sally   3   8
Joe     1   4
Bob     3   7
Mary    6   9
Sally   8   4
Bob     4   8
Joe     2   6
Joe     4   5

Formatted Data:
Mary       12      16
Sally      15      21
Bob         7      15
Joe         7      15

Untuk melakukan ini, tambahkan modul Kelas (Sisipkan -> Modul Kelas) dan ubah namanya menjadi HomeOffice. Masukkan kode ini ke dalam kelas (beberapa bagian dilewati agar tidak terlalu panjang. Isi jika diperlukan untuk menambahkan properti untuk setiap produk asuransi.)

Option Explicit

Private pOffice As String
Private pINAKI As Double
Private pINCA As Double
'... class properties left out for brevity
Private pIncidentOnly As Double


''''''''''''''''''''''
' Office property
''''''''''''''''''''''
Public Property Get Office() As String
    Office = pOffice
End Property
Public Property Let Office(Value As String)
    pOffice = Value
End Property

''''''''''''''''''''''
' INAKI property
''''''''''''''''''''''
Public Property Get INAKI() As Double
    INAKI = pINAKI
End Property
Public Property Let INAKI(Value As Double)
    pINAKI = Value
End Property

''''''''''''''''''''''
' INCA property
''''''''''''''''''''''
Public Property Get INCA() As Double
    INCA = pINCA
End Property
Public Property Let INCA(Value As Double)
    pINCA = Value
End Property

''''''''''''''''''''''
' Add other propertied for the different product types
''''''''''''''''''''''
' Follow the same format as the other properties

''''''''''''''''''''''
' IncidentOnly property
''''''''''''''''''''''
Public Property Get IncidentOnly() As Double
    IncidentOnly = pIncidentOnly
End Property
Public Property Let IncidentOnly(Value As Double)
    pIncidentOnly = Value
End Property

Sekarang di sub CommandButton23_Click Anda tambahkan kode ini (sekali lagi disingkat agar singkatnya, tapi semoga Anda mendapatkan gambarannya.):

Sub test()
    Dim col As Collection
    Dim r As Integer
    Dim c As Integer
    Dim HO As New HomeOffice

    'Collections can only have one Item, Key pair. 
    'We'll use the office location as the key to get a 
    'unique list of offices
    Set col = New Collection

    'Read in the raw data
    With Sheet1
        For r = 1 To .UsedRange.Rows.Count
            'Check if the location has an existing HomeOffice object 
            If InCol(col, .Cells(r, 1)) Then
                'It does so get the existing object and total the values
                Set HO = col.Item(.Cells(r, 1))
                HO.Office = .Cells(r, 1)
                HO.INAKI = HO.INAKI + .Cells(r, 2)
                HO.INCA = HO.INCA + .Cells(r, 3)
                ' more properties
                HO.IncidentOnly = HO.IncidentOnly + .Cells(r, 10)
                'We have to remove the existing object and add it again
                'to reflect the updated totals
                col.Remove (.Cells(r, 1))
            Else
                'The location hasn't been added yet so create and add it
                HO.Office = .Cells(r, 1)
                HO.INAKI = .Cells(r, 2)
                HO.INCA = .Cells(r, 3)
                ' More properties
                HO.IncidentOnly = .Cells(r, 10)
            End If
            col.Add HO, .Cells(r, 1)
            'Important to clear our object or our totals are wrong! :)
            Set HO = Nothing
        Next r
    End With

    'Now we simply loop through our collection of offices and
    'print out the totals.
    r = 6 'The first office starts on row 6 in your picture
    With Sheet2
        For Each HO In col
            .Cells(r, "A").Value = HO.Office
            .Cells(r + 1, "C").Value = "IN - AK, HI"
            .Cells(r + 1, "F").Value = HO.INAKI
            .Cells(r + 2, "C").Value = "IN - CA"
            .Cells(r + 2, "F").Value = HO.INCA
            'Continuing on for all 10 types
            .Cells(r + 10, "C").Value = "Incident Only"
            .Cells(r + 10, "F").Value = HO.IncidentOnly
            Set HO = Nothing
            r = r + 13 'So the next office starts 13 rows later...Row 19 in your pic
        Next
    End With
End Sub

Function InCol(col As Collection, key As Variant) As Boolean
    'Returns TRUE if the object is in the collection or FALSE if it is not
    Dim obj As New HomeOffice

    On Error GoTo err
    InCol = True
    'If the key doesn't exist, it throws an error and set the function to false
    Set obj = col(key)
    Set obj = Nothing
    Exit Function

err:
        InCol = False
End Function

Ini adalah pendekatan yang sangat berbeda, dan melibatkan beberapa konsep yang lebih ketat. Seperti yang saya katakan, ini mungkin tidak berfungsi tergantung pada bagaimana data mentah diformat, tapi mungkin ini bisa memberi Anda cara berbeda untuk mengatasi masalah Anda.

person Tim    schedule 24.11.2015
comment
Saya sangat menghargai tanggapannya. Saya akan mencoba mengadaptasi fungsi-fungsi ini ke proyek saya. Satu-satunya masalah yang dapat saya lihat sebelumnya adalah tidak setiap klien dikenakan tarif yang sama, untuk negara bagian yang sama. contoh: sementara satu klien mungkin dikenakan tarif yang sama untuk klaim yang terjadi di TX & CA, klien lain mungkin dikenakan tarif terpisah untuk TX & CA. proses ini melibatkan banyak variabel dinamis yang harus saya pertimbangkan. Membuat template universal, atau setidaknya template yang dapat melayani 9/10 klien terbukti merupakan tugas yang berat. - person Graham Chandler; 24.11.2015
comment
Saya tidak memiliki pengetahuan tentang array, tapi sepertinya saya harus bisa menyimpan data mentah dalam array dan menariknya berdasarkan kriteria variabel (Adjuster Home Office, Line Type, Coverage Code, Claim Type, State of Jurisdiction, dll. ). Tujuan utama saya adalah mengatur data mentah dengan Adjuster Home Office. Lalu saya harus bisa memberi tahu makro apa yang saya cari, dan mengaturnya berdasarkan kriteria yang saya berikan. - person Graham Chandler; 24.11.2015
comment
Jika Anda ingin mengambil data berdasarkan kriteria, Anda menginginkan koleksi, bukan array. Koleksi pada dasarnya adalah larik 2 elemen bertipe Key, Value. Dalam jawaban saya, kuncinya adalah kantor dan nilainya adalah objek yang memiliki semua properti data Anda (misalnya, array array yang longgar). Jadi, Anda dapat mengambil data masing-masing kantor dengan kode set HO = col.Item("BOCA RATON, FL") Kemudian Anda dapat melihat statistik individual untuk kantor tersebut seperti ini: HO.MedicalOnly (dengan asumsi Anda membuat properti MedicalOnly di Modul Kelas. - person Tim; 24.11.2015
comment
Tidak jelas dari contoh data bagaimana negara bagian yang berbeda dengan tarif yang berbeda berkorelasi dengan contoh apa yang ingin Anda dapatkan. Jika didasarkan pada Negara Yurisdiksi, salah satu properti HomeOffice Anda mungkin adalah SoJ. Kemudian Anda dapat menggunakan pernyataan Select Case untuk menentukan tarif yang harus diterapkan pada negara bagian tersebut. Misalnya, Select Case HO.SoJ Case "MN", "TX", "CA" Rate = 1.5 End Select - person Tim; 24.11.2015
comment
Saya menambahkan gambar tujuan saya. Jika ini tidak mungkin, biarlah. Saya hanya harus bergerak ke arah yang berbeda - person Graham Chandler; 24.11.2015
comment
Mudah-mudahan itu bukan Nomor Rekening yang sebenarnya! :) Tapi ya, kode yang saya posting akan melakukan itu. Ini semua masalah penataan loop Anda untuk meletakkan data di tempat yang Anda inginkan. Saya akan mengedit kode dalam jawaban saya untuk membuatnya dicetak seperti gambar Anda. - person Tim; 24.11.2015
comment
haha Saya baru saja menghapus akun # itu. sebagian besar hanya fiksi, tapi lebih baik aman daripada menyesal. Terima kasih! - person Graham Chandler; 24.11.2015
comment
ini tampaknya statis bagi saya. Item Baris seringkali berbeda untuk setiap klien. Item baris, negara bagian, tarif, semuanya merupakan variabel dan saya tidak melihat bagaimana hal ini memberi saya fleksibilitas yang saya perlukan. Saya menambahkan gambar lain yang menunjukkan dari mana daftar item baris diisi oleh formulir pengguna, dan diimpor. - person Graham Chandler; 24.11.2015
comment
Ahh... Maafkan aku karena telah membawamu ke jalan yang salah. Terlihat dari gambar bahwa setiap kantor (Atlanta, Aurora, Boca, dll) masing-masing memiliki 10 kategori yang sama persis. Ini mungkin bukan metode terbaik untuk kebutuhan Anda. Maaf! :( - person Tim; 24.11.2015
comment
jangan khawatir, saya menghargai usahanya. Seharusnya aku lebih jelas di depan. - person Graham Chandler; 24.11.2015