我不知道或不记得我正在寻找的内容的技术名称,但我认为一个例子足以让您准确理解我正在寻找的内容。
给定表格A
a x1
b x2
c x1
和表 B
x1 x
x1 y
x1 z
x2 p
x2 z
我需要桌子C
a x
a y
a z
b p
b z
c x
c y
c z
我正在寻找一个或一组公式来获取表 C
我想只需要在 C 表上添加一个额外的行,其中表 A 上第一列的每个值对于 TableA!Column2 到 TableB!Column1 的每个对应值但是我可以'不知道如何
我认为这是一个简单的 SQL Inner Join。
您想要做的是 SQL 中的 JOIN,它会重复值。 Inner、left、right 或 full 定义了两侧都没有匹配项时的行为。
我能想到的最简单的方法是使用 Google Apps 脚本 制作一个在公式中使用的自定义函数:
function JOINRANGES(range1, index1, range2, index2) {
const result = []
for(let row1 of range1) {
for (let row2 of range2) {
if (row1[index1] == row2[index2]) {
const r = [...row1, ...row2]
// Remove the keys themselves
r.splice(row1.length+index2, 1)
r.splice(index1, 1)
result.push(r)
}
}
}
return result
}
然后您可以在左上角列的表格公式中使用它:
=ARRAYFORMULA(JOINRANGES(A1:B3, 1, D1:E6, 0))
第一个和第三个参数是范围,第二个和第四个参数是范围内列的索引(从0开始)。
最终结果:
google-apps-script
标签中的“关于”页面有很多非常有用的指南和文档。
尝试:
=ARRAYFORMULA({TRIM(FLATTEN(SPLIT(QUERY(REPT(IF($A2:A="",,$A2:A&"♦"), IFNA(VLOOKUP($B2:$B, QUERY({$D2:$D},
"select Col1,count(Col1) where Col1 is not null group by Col1"), 2, 0))),,9^9), "♦"))), IFNA(VLOOKUP(
TRIM(FLATTEN(SPLIT(QUERY(REPT(IF($A2:A="",,$B2:B&"♦"), IFNA(VLOOKUP($B2:$B, QUERY({$D2:$D},
"select Col1,count(Col1) where Col1 is not null group by Col1"), 2, 0))),,9^9), "♦")))&COUNTIFS(
TRIM(FLATTEN(SPLIT(QUERY(REPT(IF($A2:A="",,$A2:A&"♦"), IFNA(VLOOKUP($B2:$B, QUERY({$D2:$D},
"select Col1,count(Col1) where Col1 is not null group by Col1"), 2, 0))),,9^9), "♦"))),
TRIM(FLATTEN(SPLIT(QUERY(REPT(IF($A2:A="",,$A2:A&"♦"), IFNA(VLOOKUP($B2:$B, QUERY({$D2:$D},
"select Col1,count(Col1) where Col1 is not null group by Col1"), 2, 0))),,9^9), "♦"))), ROW(INDIRECT("O1:O"&COUNTA(
TRIM(FLATTEN(SPLIT(QUERY(REPT(IF($A2:A="",,$B2:B&"♦"), IFNA(VLOOKUP($B2:$B, QUERY({$D2:$D},
"select Col1,count(Col1) where Col1 is not null group by Col1"), 2, 0))),,9^9), "♦")))))), "<="&ROW(INDIRECT("O1:O"&COUNTA(
TRIM(FLATTEN(SPLIT(QUERY(REPT(IF($A2:A="",,$B2:B&"♦"), IFNA(VLOOKUP($B2:$B, QUERY({$D2:$D},
"select Col1,count(Col1) where Col1 is not null group by Col1"), 2, 0))),,9^9), "♦"))))))),
{D2:D&COUNTIFS(D2:D, D2:D, ROW(O2:O), "<="&ROW(O2:O)), E2:E}, 2, 0))})
Las 答案不适用于 TableA!column1 上的重复项。 显示关键公式的说明:
只需添加一个中间列
JOIN(",",FILTER(E$2:E,D$2:D=L2))
这样你就可以从他们那里获取数据
INDEX(TRANSPOSE(SPLIT(JOIN(",",FILTER(M$2:M,K$2:K=O2)),",")),COUNTIF(O$1:O1,"="&O2)+1)
进入相乘的列
ArrayFormula(TRIM(FLATTEN(SPLIT(QUERY(REPT(IF(A2:A="",,A2:A&"♦"), IFNA(VLOOKUP(B2:B, QUERY({D2:D}, "select Col1,count(Col1) where Col1 is not null group by Col1"), 2, 0))),,9^9), "♦"))))
这是一个例子和一张图片。
我想要与 @Marti 发布的 Apps 脚本略有不同的行为。此实现类似于 Pandas DataFrame.merge:输入范围应具有列名称,它会检测哪些列匹配,然后在这些列上的行为类似于 SQL
INNER JOIN
。
它还允许输入范围包含空行,因此像
A1:D
这样延伸到文件末尾的范围不会导致过多的处理/输出。
使用示例:
function JOINRANGES(range1, range2) {
const combinedrange = [];
const matchingindices = findmatchingindices(range1[0], range2[0]);
const range1keys = matchingindices[0];
const range2keys = matchingindices[1];
for (let row1i = 0; row1i < range1.length; row1i++) {
const row1 = range1[row1i];
if (isemptyrow(row1)) {
break; // done if we get to an empty row
}
let rowcount2 = 0;
for (let row2i = 0; row2i < range2.length; row2i++) {
const row2 = range2[row2i];
if (isemptyrow(row2)) {
break; // done if we get to an empty row
}
// Check if the rows match at all key indices.
let matched = true;
for (let ki = 0; ki < range1keys.length; ki++) {
if (row1[range1keys[ki]] != row2[range2keys[ki]]) {
matched = false;
}
}
if (!matched) {
continue;
}
// If it's a match, combine the rows. Start with row1 contents.
const combinedrow = [...row1];
// Copy in row 2 but skip the matched indices.
for (let i = 0; i < row2.length; i++) {
let skipindex = false
for (let ki = 0; ki < range2keys.length; ki++) {
if (i == range2keys[ki]) {
skipindex = true;
}
}
if (!skipindex) {
combinedrow.push(row2[i]);
}
}
combinedrange.push(combinedrow);
}
}
console.log(`Processed ${range1.length} + ${range2.length} rows for ${combinedrange.length} matches.`)
return combinedrange;
}
// Compare two lists of column header names.
// Return the list of which indices match for each input.
// For example:
// ["a", "b", "x"], ["a", "x", "z"] => [[0, 2], [0, 1]]
// Indices 0 and 2 from the first list match
// indices 0 and 1 from the second list respectively.
function findmatchingindices(headers1, headers2) {
const matching1 = [];
const matching2 = [];
for (let h1i = 0; h1i < headers1.length; h1i++) {
for (let h2i = 0; h2i < headers2.length; h2i++) {
if (headers1[h1i] == headers2[h2i]) {
matching1.push(h1i);
matching2.push(h2i);
}
}
}
return [matching1, matching2];
}
function isemptyrow(row) {
for (let i = 0; i < row.length; i++) {
if (row[i] != '') {
return false;
}
}
return true;
}
我不经常使用js,所以我确信它可能更惯用,但在我的测试用例中有效。