Google 电子表格中的内连接

问题描述 投票:0回答:4

我不知道或不记得我正在寻找的内容的技术名称,但我认为一个例子足以让您准确理解我正在寻找的内容。

给定表格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!Column2TableB!Column1 的每个对应值但是我可以'不知道如何

我认为这是一个简单的 SQL Inner Join。

arrays google-sheets google-sheets-formula flatten google-query-language
4个回答
3
投票

您想要做的是 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开始)。

最终结果:

Screenshot of the result

如果您不了解 Google Apps 脚本,

google-apps-script
标签中的“关于”页面有很多非常有用的指南和文档。


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), "♦"))), 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))})

enter image description here


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), "♦"))))

这是一个例子和一张图片。 enter image description here


0
投票

我想要与 @Marti 发布的 Apps 脚本略有不同的行为。此实现类似于 Pandas DataFrame.merge:输入范围应具有列名称,它会检测哪些列匹配,然后在这些列上的行为类似于 SQL

INNER JOIN

它还允许输入范围包含空行,因此像

A1:D
这样延伸到文件末尾的范围不会导致过多的处理/输出。

使用示例:

gsheet showing formula usage

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,所以我确信它可能更惯用,但在我的测试用例中有效。

© www.soinside.com 2019 - 2024. All rights reserved.