英文:
How to populate data that don't match specific criteria in table?
问题
I have 2 tabs, 1 Summary tab and the other 1 is Data tab. The summary tab contains a table with specific customer numbers(as shown in the summary table below).
我有两个选项卡,一个是汇总选项卡,另一个是数据选项卡。汇总选项卡包含一个具有特定客户号码的表格(如下所示)。
I'm trying to achieve the same set of data and columns that are listed in the summary table but for the rest of the customer numbers that do not exist in the summary table and insert them in a listbox.
我试图实现与汇总表中列出的相同的数据和列,但对于汇总表中不存在的其余客户号码,并将它们插入到一个列表框中。
Can anyone help me please with that?
有人能帮助我吗?
Thank you!
谢谢!
My Summary Table:
我的汇总表格:
Customer Number | Customer Name | aged debt | Count of invoices | Value |
---|---|---|---|---|
55850 | ABC | 1-30 | 2 | 2516 |
55850 | ABC | 30-60 | 1 | 52635 |
55850 | ABC | 60-90 | 1 | 102754 |
55850 | ABC | 90-120 | 1 | 152873 |
55850 | ABC | 120-180 | 1 | 202992 |
32336 | DEF | 30-60 | 2 | 253111 |
32336 | DEF | 60-90 | 2 | 303230 |
30131 | GHI | 1-30 | 1 | 353349 |
30131 | GHI | 30-60 | 2 | 403468 |
30131 | GHI | 60-120 | 2 | 453587 |
13914 | JKL | 1-30 | 2 | 503706 |
13914 | JKL | 30-60 | 2 | 553825 |
13914 | JKL | 60-90 | 2 | 603944 |
13914 | JKL | 90-120 | 1 | 654063 |
我的汇总表格:
客户号码 | 客户名称 | 逾期债务 | 发票数 | 价值 |
---|---|---|---|---|
55850 | ABC | 1-30 | 2 | 2516 |
55850 | ABC | 30-60 | 1 | 52635 |
55850 | ABC | 60-90 | 1 | 102754 |
55850 | ABC | 90-120 | 1 | 152873 |
55850 | ABC | 120-180 | 1 | 202992 |
32336 | DEF | 30-60 | 2 | 253111 |
32336 | DEF | 60-90 | 2 | 303230 |
30131 | GHI | 1-30 | 1 | 353349 |
30131 | GHI | 30-60 | 2 | 403468 |
30131 | GHI | 60-120 | 2 | 453587 |
13914 | JKL | 1-30 | 2 | 503706 |
13914 | JKL | 30-60 | 2 | 553825 |
13914 | JKL | 60-90 | 2 | 603944 |
13914 | JKL | 90-120 | 1 | 654063 |
My Data source
我的数据源
Customer Number | Customer Name | Invoice Number | Invoice Date | Flag | aged debt | Value | area |
---|---|---|---|---|---|---|---|
55850 | ABC | 121 | 01/01/2022 | Yes | 1-30 | 1258 | ES |
55850 | ABC | 122 | 02/01/2022 | Yes | 1-30 | 1258 | WE |
55850 | ABC | 123 | 03/01/2022 | Yes | 30-60 | 52635 | NO |
55850 | ABC | 124 | 04/01/2022 | No | 60-90 | 102754 | SO |
55850 | ABC | 125 | 05/01/2022 | Yes | 90-120 | 152873 | ES |
55850 | ABC | 126 | 06/01/2022 | Yes | 120-180 | 202992 | WE |
32336 | DEF | 127 | 07/01/2022 | No | 30-60 | 126555.5 | NO |
32336 | DEF | 128 | 08/01/2022 | Yes | 30-60 | 126555.5 | SO |
32336 | DEF | 129 | 09/01/2022 | Yes | 60-90 | 151615 | ES |
32336 | DEF | 130 | 10/01/2022 | No | 60-90 | 151615 | WE |
30131 | GHI | 131 | 11/01/2022 | Yes | 1-30 | 353349 | NO |
英文:
I have 2 tabs, 1 Summary tab and the other 1 is Data tab. The summary tab contains a table with specific customer numbers(as shown in the summary table below).
I'm trying to achieve the same set of data and columns that are listed in the summary table but for the rest of the customer numbers that do not exist in the summary table and insert them in a listbox.
can anyone help me please with that?
Thank you!
My Summary Table:
Customer Number | Customer Name | aged debt | Count of invoices | Value |
---|---|---|---|---|
55850 | ABC | 1-30 | 2 | 2516 |
55850 | ABC | 30-60 | 1 | 52635 |
55850 | ABC | 60-90 | 1 | 102754 |
55850 | ABC | 90-120 | 1 | 152873 |
55850 | ABC | 120-180 | 1 | 202992 |
32336 | DEF | 30-60 | 2 | 253111 |
32336 | DEF | 60-90 | 2 | 303230 |
30131 | GHI | 1-30 | 1 | 353349 |
30131 | GHI | 30-60 | 2 | 403468 |
30131 | GHI | 60-120 | 2 | 453587 |
13914 | JKL | 1-30 | 2 | 503706 |
13914 | JKL | 30-60 | 2 | 553825 |
13914 | JKL | 60-90 | 2 | 603944 |
13914 | JKL | 90-120 | 1 | 654063 |
My Data source
Customer Number | Customer Name | Invoice Number | Invoice Date | Flag | aged debt | Value | area |
---|---|---|---|---|---|---|---|
55850 | ABC | 121 | 01/01/2022 | Yes | 1-30 | 1258 | ES |
55850 | ABC | 122 | 02/01/2022 | Yes | 1-30 | 1258 | WE |
55850 | ABC | 123 | 03/01/2022 | Yes | 30-60 | 52635 | NO |
55850 | ABC | 124 | 04/01/2022 | No | 60-90 | 102754 | SO |
55850 | ABC | 125 | 05/01/2022 | Yes | 90-120 | 152873 | ES |
55850 | ABC | 126 | 06/01/2022 | Yes | 120-180 | 202992 | WE |
32336 | DEF | 127 | 07/01/2022 | No | 30-60 | 126555.5 | NO |
32336 | DEF | 128 | 08/01/2022 | Yes | 30-60 | 126555.5 | SO |
32336 | DEF | 129 | 09/01/2022 | Yes | 60-90 | 151615 | ES |
32336 | DEF | 130 | 10/01/2022 | No | 60-90 | 151615 | WE |
30131 | GHI | 131 | 11/01/2022 | Yes | 1-30 | 353349 | NO |
30131 | GHI | 132 | 12/01/2022 | Yes | 30-60 | 201734 | SO |
30131 | GHI | 133 | 13/01/2022 | No | 30-60 | 201734 | ES |
30131 | GHI | 134 | 14/01/2022 | No | 60-120 | 226793.5 | WE |
30131 | GHI | 135 | 15/01/2022 | Yes | 60-120 | 226793.5 | NO |
13914 | JKL | 136 | 16/01/2022 | Yes | 1-30 | 251853 | SO |
13914 | JKL | 137 | 17/01/2022 | Yes | 1-30 | 251853 | ES |
13914 | JKL | 138 | 18/01/2022 | Yes | 30-60 | 276912.5 | WE |
13914 | JKL | 139 | 19/01/2022 | Yes | 30-60 | 276912.5 | NO |
13914 | JKL | 140 | 20/01/2022 | Yes | 60-90 | 301972 | SO |
13914 | JKL | 141 | 21/01/2022 | Yes | 60-90 | 301972 | ES |
13914 | JKL | 142 | 22/01/2022 | Yes | 90-120 | 654063 | WE |
13900 | LMN | 143 | 23/01/2022 | No | 1-30 | 120000 | NO |
13900 | LMN | 144 | 24/01/2022 | Yes | 30-60 | 180000 | SO |
13900 | LMN | 145 | 25/01/2022 | Yes | 60-90 | 50000 | ES |
13900 | LMN | 146 | 26/01/2022 | No | 90-120 | 60000 | WE |
13900 | LMN | 147 | 27/01/2022 | Yes | 120-180 | 70000 | NO |
13901 | OOO | 148 | 28/01/2022 | Yes | 30-60 | 3000 | SO |
13901 | OOO | 149 | 29/01/2022 | No | 60-90 | 40000 | ES |
13901 | OOO | 150 | 30/01/2022 | No | 90-120 | 50000 | WE |
13901 | OOO | 151 | 31/01/2022 | No | 120-180 | 60000 | NO |
13902 | OOX | 152 | 01/02/2022 | No | 30-60 | 10000 | SO |
13902 | OOX | 153 | 02/02/2022 | No | 60-90 | 20000 | ES |
13902 | OOX | 154 | 03/02/2022 | Yes | 90-120 | 30000 | WE |
13902 | OOX | 155 | 04/02/2022 | Yes | 120-180 | 40000 | NO |
Option Explicit
Sub test()
Dim conn, rs As Object, sq As String, Accounts As String
Set conn = CreateObject("ADODB.Connection")
With conn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.ConnectionString = "Data Source=" &
ThisWorkbook.FullName & ";" & _
"Extended Properties=""Excel 12.0
Xml;HDR=Yes;IMEX=1"";"
.Open
End With
sq = "SELECT T1.[Customer Number],T1.
[Customer Name],T1.[Aged Debt] " & _
"COUNT(T1.[Invoice Number]) as [count of Invoices] " & _
"sum(T1.[Value]) as [values] " & _
"FROM[Data$] T1 " & _
"WHERE T1.[Customer Number] Not In (" & Getcust(Accounts) & ") " & _
"GROUP BY T1.[Customer Number],T1.[Customer Name],T1.[Aged Debt]"
Set rs = conn.Execute(sq)
If Not rs.EOF Then
With Me.listbox1
.Value = ""
.Column = rs.GetRows
.ColumnCount = rs.Fields.Count
.ColumnHeads = False
.ColumnWidths = "90,90,50,50,180"
End With
End If
rs.Close
conn.Close
Set rs = npthing
Set conn = Nothing
End Sub
Public Function Getcust(Accounts As String) As String
Dim dU1 As Object, cU1 As Variant, iU1 As Long, i As Integer
Set dU1 = CreateObject("Scripting.Dictionary")
cU1 = Sheets("Summary").ListObjects(1).ListColumns("Customer
Number").DataBodyRange
For iU1 = 1 To UBound(cU1, 1)
dU1(cU1(iU1, 1)) = 1
Next iU1
Accounts = "'"
For i = 0 To dU1.Count - 1
Accounts = Accounts & dU1.Keys()(i) & "','"
Next
Accounts = Left(Accounts, Len(Accounts) - 5)
Getcust = Accounts
End Function
答案1
得分: 0
Here are the translated parts of your code:
Write two Connection Only Power queries to read your Summary Data and your Datasource
Then Merge those queries using a LeftAnti join to get only the rows in data source that do not exist in the summary.
You can then use Transform, Group By to get the details you need for your summary e.g.
let
Source = Table.NestedJoin(DataSource, {"Customer Number"}, Summary, {"Customer Number"}, "Summary", JoinKind.LeftAnti),
#"Grouped Rows" = Table.Group(Source, {"Customer Number", "Customer Name", "aged debt"}, {{"Count of invoices", each Table.RowCount(_), Int64.Type}, {"Value", each List.Sum([Value]), type nullable number}})
in
#"Grouped Rows"
Please note that I've left the code in its original format and haven't translated the actual Power Query code.
英文:
Write two Connection Only Power queries to read your Summary Data and your Datasource
Then Merge those queries using a LeftAnti join to get only the rows in data source that do not exist in the summary.
You can then use Transform, Group By to get the details you need for your summary e.g.
let
Source = Table.NestedJoin(DataSource, {"Customer Number"}, Summary, {"ustomer Number"}, "Summary", JoinKind.LeftAnti),
#"Grouped Rows" = Table.Group(Source, {"Customer Number", "Customer Name", "aged debt"}, {{"Count of invoices", each Table.RowCount(_), Int64.Type}, {"Value", each List.Sum([Value]), type nullable number}})
in
#"Grouped Rows"
答案2
得分: 0
请使用标准的方式。您必须从真正存在的地方(工作表)设置lisObjects(表格)。活动工作表必须包含一个名为 "ListBox1" 的 ActiveX 列表框:
Sub LoadListBoxWithNotExistingCustomNo()
Dim tbl1 As ListObject, tbl2 As ListObject, arrT1, arrT2, arrUnique, mtch, arrIt, arFin
Dim i As Long, j As Long, dict As New Scripting.Dictionary
Dim listB As msforms.listbox
'在此处使用两个涉及的表格真正存在的工作表:
Set tbl1 = ActiveSheet.ListObjects("T1.") '第一个表格对象
Set tbl2 = ActiveSheet.ListObjects("T2.") '第二个表格对象
arrT1 = tbl1.DataBodyRange.Value2 '将它们的内容放入数组以加快处理速度
arrT2 = tbl2.DataBodyRange.Value2
For i = 1 To UBound(arrT1)
dict(arrT1(i, 1)) = vbNullString '提取唯一的客户号码
Next i
arrUnique = dict.keys '将字典键放入数组中
dict.RemoveAll '清空字典以重新使用它...
'在字典中加载必要的数据:
For i = 1 To UBound(arrT2)
mtch = Application.Match(arrT2(i, 1), arrUnique, True)
If Not IsNumeric(mtch) Then
If Not dict.Exists(arrT2(i, 1) & "|" & arrT2(i, 6)) Then
dict.Add arrT2(i, 1) & "|" & arrT2(i, 6), Array(1, arrT2(i, 2), arrT2(i, 7))
Else
arrIt = dict(arrT2(i, 1) & "|" & arrT2(i, 6)) '将项目放入数组中
arrIt(0) = arrIt(0) + 1 '计算出现次数
arrIt(2) = arrIt(2) + arrT2(i, 7) '添加值
dict(arrT2(i, 1) & "|" & arrT2(i, 6)) = arrIt '将更新后的项目数组放回
End If
End If
Next i
'加载最终数组:
ReDim arFin(1 To dict.count, 1 To 5)
For i = 1 To dict.count
arFin(i, 1) = Split(dict.keys()(i - 1), "|")(0) '客户编号
arFin(i, 3) = Split(dict.keys()(i - 1), "|")(1) '拖欠的延迟
arFin(i, 2) = dict.Items(i - 1)(1) '客户名
arFin(i, 4) = dict.Items(i - 1)(0) '发票数
arFin(i, 5) = dict.Items(i - 1)(2) '发票数
Next i
Set listB = ActiveSheet.OLEObjects("ListBox1").Object: '设置ActiveX列表框
With listB
.ColumnCount = UBound(arFin, 2) '设置列表框的列数
.List = arFin '将数组内容放入列表框
End With
End Sub
已编辑 以使用 Worksheets
而不是表格:
Sub LoadListBoxWithNotExistingCustomNoInSheets()
Dim ws1 As Worksheet, ws2 As Worksheet, arrT1, arrT2, arrUnique, mtch, arrIt, arFin
Dim i As Long, j As Long, dict As Object
Dim listB As msforms.listbox
Set ws1 = ActiveSheet '在此处使用您需要的工作表("My Summary Table")
Set ws2 = ActiveSheet '一样的。我使用相同的工作表,因为我有两个表格,现在转化为范围("My Data source")...
Dim lastR As Long
lastR = ws1.Range("A" & ws1.Rows.Count).End(xlUp).Row '第一个表格的最后一行
arrT1 = ws1.Range("A2:E" & lastR).Value2 '将其内容放入数组以加快处理速度
lastR = ws2.Range("H" & ws2.Rows.Count).End(xlUp).Row '第二个表格的最后一行(注意要使用第一个范围列)
arrT2 = ws1.Range("H2:N" & lastR).Value2 '您应该根据第二个工作表("My Data source")中需要的列来使用范围...
Set dict = CreateObject("Scripting.Dictionary")
'................
'现有代码保持不变...
End Sub
如果与代码注释相关的某些内容不够清楚,请不要犹豫,要求澄清。
英文:
Please, use the next standard way. You must set your lisObjects (tables) from the place (worksheets) where they really exist. The active sheet must contain an ActiveX
listbox, named "ListBox1":
Sub LoadListBoxWithNotExistingCustomNo()
Dim tbl1 As ListObject, tbl2 As ListObject, arrT1, arrT2, arrUnique, mtch, arrIt, arFin
Dim i As Long, j As Long, dict As New Scripting.Dictionary
Dim listB As msforms.listbox
'use here the real sheets where the two involved tables exist:
Set tbl1 = ActiveSheet.ListObjects("T1.") 'the first table Object
Set tbl2 = ActiveSheet.ListObjects("T2.") 'the second table Object
arrT1 = tbl1.DataBodyRange.Value2 'place their contents in an array for faster processing
arrT2 = tbl2.DataBodyRange.Value2
For i = 1 To UBound(arrT1)
dict(arrT1(i, 1)) = vbNullString 'extract the unique Customers numbers
Next i
arrUnique = dict.keys 'place the dictionary keys in an array
dict.RemoveAll 'empty the dictionary to reuse it...
'load in the dictionary the necessary data:
For i = 1 To UBound(arrT2)
mtch = Application.match(arrT2(i, 1), arrUnique, True)
If Not IsNumeric(mtch) Then
If Not dict.Exists(arrT2(i, 1) & "|" & arrT2(i, 6)) Then
dict.Add arrT2(i, 1) & "|" & arrT2(i, 6), Array(1, arrT2(i, 2), arrT2(i, 7))
Else
arrIt = dict(arrT2(i, 1) & "|" & arrT2(i, 6)) 'place the item in an array
arrIt(0) = arrIt(0) + 1 'count the number of occurrences
arrIt(2) = arrIt(2) + arrT2(i, 7) 'add the values
dict(arrT2(i, 1) & "|" & arrT2(i, 6)) = arrIt 'drop back the updatred ltem array
End If
End If
Next i
'load the final array:
ReDim arFin(1 To dict.count, 1 To 5)
For i = 1 To dict.count
arFin(i, 1) = Split(dict.keys()(i - 1), "|")(0) 'the customer Number
arFin(i, 3) = Split(dict.keys()(i - 1), "|")(1) 'the aged delay
arFin(i, 2) = dict.Items(i - 1)(1) 'Customer name
arFin(i, 4) = dict.Items(i - 1)(0) 'Count of Invoices
arFin(i, 5) = dict.Items(i - 1)(2) 'Count of Invoices
Next i
Set listB = ActiveSheet.OLEObjects("ListBox1").Object: 'set the ActiveX list box
With listB
.ColumnCount = UBound(arFin, 2) 'set the list box number of columns
.List = arFin 'drop the array content in the list box
End With
End Sub
Edited for using Worksheets
instead of Tables:
Sub LoadListBoxWithNotExistingCustomNoInSheets()
Dim ws1 As Worksheet, ws2 As Worksheet, arrT1, arrT2, arrUnique, mtch, arrIt, arFin
Dim i As Long, j As Long, dict As Object
Dim listB As msforms.listbox
Set ws1 = ActiveSheet 'use here the sheet you need ("My Summary Table")
Set ws2 = ActiveSheet 'the same. I am using the same sheet because I had two tables, now transformed in ranges ("My Data source")...
Dim lastR As Long
lastR = ws1.Range("A" & ws1.rows.count).End(xlUp).row 'last row for the former first table
arrT1 = ws1.Range("A2:E" & lastR).Value2 'place their contents in an array for faster processing
lastR = ws2.Range("H" & ws2.rows.count).End(xlUp).row 'last row for the former second table (take care of the first range column TO BE USED)
arrT2 = ws1.Range("H2:N" & lastR).Value2 'you should use your range in terms of necessary columns from second sheet ("My Data source")...
Set dict = CreateObject("Scripting.Dictionary")
'................
'the existing code remains unchanged...
End Sub
If something not clear enough related to the code comments, do not hesitate to ask for clarifications.
Edit 2
Microsoft Scripting Runtime
reference can be added running the next piece of code:
Sub addScrRunTimeRef()
'Add a reference to 'Microsoft Scripting Runtime':
'In case of error ('Programmatic access to Visual Basic Project not trusted'):
'Options->Trust Center->Trust Center Settings->Macro Settings->Developer Macro Settings->
' check "Trust access to the VBA project object model"
Application.vbE.ActiveVBProject.References.AddFromFile "C:\Windows\SysWOW64\scrrun.dll"
End Sub
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论