是否有一种方法可以在excel中执行交叉连接或笛卡尔积?

fjnneemd  于 2023-06-25  发布在  其他
关注(0)|答案(7)|浏览(213)

目前,我不能使用一个典型的数据库,所以我暂时使用Excel.有什么想法吗

bq9c1y66

bq9c1y661#

这里有三个维度:dim1(ABC)、dim2(123)、dim3(XYZ)。
以下是如何使用标准Excel而不使用VBA制作二维笛卡尔积:
1)垂直绘制dim 1,水平绘制dim 2。在交点上连接维成员:

2)取消透视数据。使用ALT-D-P启动透视表向导(不要按住ALT,按一次)。选择“多个合并范围”-->创建单个页面。-->选择所有单元格(包括标题!)并将其添加到列表中,请按下一步。

3)垂直绘制结果并分解连接的字符串

瞧,你有交叉连接。如果需要添加另一个尺寸,请再次重复此算法。
干杯
康斯坦丁

hgb9j2n6

hgb9j2n62#

这里有一个非常简单的方法来生成任意数量的列表的笛卡尔积,使用透视表:
https://chandoo.org/wp/generate-all-combinations-from-two-lists-excel/
这个例子是针对两个列表的,但它适用于任何数量的表和/或列。
在创建数据透视表之前,您需要convert your value lists to tables

jvlzgdj9

jvlzgdj93#

使用VBA可以。下面是一个小例子:

Sub SqlSelectExample()
'list elements in col C not present in col B
    Dim con As ADODB.Connection
    Dim rs As ADODB.Recordset
    Set con = New ADODB.Connection
    con.Open "Driver={Microsoft Excel Driver (*.xls)};" & _
           "DriverId=790;" & _
           "Dbq=" & ThisWorkbook.FullName & ";" & _
           "DefaultDir=" & ThisWorkbook.FullName & ";ReadOnly=False;"
    Set rs = New ADODB.Recordset
    rs.Open "select ccc.test3 from [Sheet1$] ccc left join [Sheet1$] bbb on ccc.test3 = bbb.test2 where bbb.test2 is null  ", _
            con, adOpenStatic, adLockOptimistic
    Range("g10").CopyFromRecordset rs   '-> returns values without match
    rs.MoveLast
    Debug.Print rs.RecordCount          'get the # records
    rs.Close
    Set rs = Nothing
    Set con = Nothing
End Sub
kognpnkq

kognpnkq4#

以下是使用Excel公式的方法:

|    |       A        |       B        |       C        |
| -- | -------------- | -------------- | -------------- |
|  1 |                |                |                |
| -- | -------------- | -------------- | -------------- |
|  2 | Table1_Column1 | Table2_Column1 | Table2_Column2 |
| -- | -------------- | -------------- | -------------- |
|  3 |       A        |       1        |       X        |
| -- | -------------- | -------------- | -------------- |
|  4 |       B        |       2        |       Y        |
| -- | -------------- | -------------- | -------------- |
|  5 |       C        |       3        |       Z        |
| -- | -------------- | -------------- | -------------- |
|  6 |                |                |                |
| -- | -------------- | -------------- | -------------- |
|  7 |      Col1      |      Col2      |      Col3      |
| -- | -------------- | -------------- | -------------- |
|  8 |   = Formula1   |   = Formula2   |   = Formula3   |
| -- | -------------- | -------------- | -------------- |
|  9 |   = Formula1   |   = Formula2   |   = Formula3   |
| -- | -------------- | -------------- | -------------- |
| 10 |   = Formula1   |   = Formula2   |   = Formula3   |
| -- | -------------- | -------------- | -------------- |
| 11 |      ...       |      ...       |      ...       |
| -- | -------------- | -------------- | -------------- |

Formula1: IF(ROW() >= 8 + (3*3*3), "", INDIRECT(ADDRESS(3 + MOD(FLOOR(ROW() - 8)/(3*3), 3), 1)))
Formula2: IF(ROW() >= 8 + (3*3*3), "", INDIRECT(ADDRESS(3 + MOD(FLOOR(ROW() - 8)/(3)  , 3), 2)))
Formula3: IF(ROW() >= 8 + (3*3*3), "", INDIRECT(ADDRESS(3 + MOD(FLOOR(ROW() - 8)/(1)  , 3), 3)))
tsm1rwdh

tsm1rwdh5#

一个 * 通用公式来统治它们!

结果

公式

MOD(CEILING.MATH([index]/PRODUCT([size of set 0]:[size of previous set]))-1,[size of current set])+1

这个公式给出了集合中每个元素的索引(有序位置),其中集合i的大小为n_i。因此,如果我们有四个集合,大小将是[n_1n_2n_3n_4]。
使用该索引,可以只使用index函数从集合中选择任何属性(假设每个集合都是一个有几个列的表,可以使用index([table of the set],[this result],[column number of attribute]))。

说明

解释了公式的两个主要组成部分,循环组成部分和分配组成部分。

循环组件

=MOD([partitioning component]-1, [size of current set])+1

  • 在集合的所有可能值之间循环。
  • modulo函数是必需的,因此结果将“绕过”集合的大小,并且永远不会“超出”可能值的范围。
  • -1+1帮助我们从基于1的编号(我们的集合索引)到zero-based编号(用于模运算)。

分区组件

CEILING.MATH([index]/PRODUCT([size of set 0]:[size of previous set])

  • 将“笛卡尔索引”划分为块,并为每个块指定“名称”。
  • “笛卡尔指数”只是从1到笛卡尔乘积中的元素数量的编号(由每个集合的大小的乘积给出)。
  • “name”只是“cartesian index”的按块递增枚举。
  • 为了让属于每个块的所有索引具有相同的“名称”,我们将“笛卡尔索引”除以分区的数量,并将结果“ceil”(四舍五入)。
  • 分区的数量是最后一个循环的总大小,因为对于每个先前的结果,需要对该集合的每个元素重复它。
  • 碰巧的是,前面结果的大小是所有前面集合大小的乘积(包括第一个集合之前的集合的大小,因此我们可以推广,我们称之为“集合0”,并且将具有恒定的大小1)。

截图

设置大小

准备集合大小,包括“Set 0”和笛卡尔积的大小。
这里,集合的大小为:

  • “Set 0”:单元格B2中的1
  • “Set 1”:单元格C2中2
  • “Set 2”:单元格D2中有5个
  • “Set 3”:单元格E2中有3个

因此,笛卡尔积的大小是30(2*5*3),在单元格A2中。

结果

表结构_tbl_CartesianProduct,包含以下列及其公式:

  • 结果如下:
  • Cartesian Index=IF(ROW()-ROW(_tbl_CartesianProduct[[#Headers];[Cartesian Index]])<=$A$2;ROW()-ROW(_tbl_CartesianProduct[[#Headers];[Cartesian Index]]);NA())
  • concatenation=TEXTJOIN("-";TRUE;_tbl_CartesianProduct[@[Index S1]:[Index S3]])
  • Index S1=MOD(CEILING.MATH([@[Cartesian Index]]/PRODUCT($B$2:B$2))-1;C$2)+1
  • Index S2=MOD(CEILING.MATH([@[Cartesian Index]]/PRODUCT($B$2:C$2))-1;D$2)+1
  • Index S3=MOD(CEILING.MATH([@[Cartesian Index]]/PRODUCT($B$2:D$2))-1;E$2)+1
  • 步骤“先前分区大小”:
  • Size prev part S1=PRODUCT($B$2:B$2)
  • Size prev part S2=PRODUCT($B$2:C$2)
  • Size prev part S3=PRODUCT($B$2:D$2)
  • 步骤“组块名称”:
  • Chunk S1=CEILING.MATH([@[Cartesian Index]]/[@[Size prev part S1]])
  • Chunk S2=CEILING.MATH([@[Cartesian Index]]/[@[Size prev part S2]])
  • Chunk S3=CEILING.MATH([@[Cartesian Index]]/[@[Size prev part S3]])
  • 最后一步“循环通过设置”:
  • Cycle chunk in S1=MOD([@[Chunk S1]]-1;C$2)+1
  • Cycle chunk in S2=MOD([@[Chunk S2]]-1;D$2)+1
  • Cycle chunk in S3=MOD([@[Chunk S3]]-1;E$2)+1

  • :用于生成笛卡尔枚举的实际工作
a6b3iqyw

a6b3iqyw6#

PowerQuery中的一些代码可以解决这个问题:

let
  Quelle = Excel.CurrentWorkbook(){[Name="tbl_Data"]}[Content],
  AddColDim2 = Table.AddColumn(Quelle, "Dim2", each Quelle[Second_col]),
  ExpandDim2 = Table.ExpandListColumn(AddColDim2, "Dim2"),
  AddColDim3 = Table.AddColumn(ExpandDim2, "Dim3", each Quelle[Third_col]),
  ExpandDim3 = Table.ExpandListColumn(AddColDim3, "Dim3"),
  RemoveColumns = Table.SelectColumns(ExpandDim3,{"Dim1", "Dim2", "Dim3"})
in RemoveColumns

8ftvxx2r

8ftvxx2r7#

尝试使用DAX CROSS JOIN。阅读更多MSDN
可以使用表达式CROSSJOIN(table1, table2)创建笛卡尔积。

相关问题