Google 表格查询 - 动态构建引用数组源

Google Sheets Query - build referenced array source dynamically

我的传播中有很多 sheetssheet (sheet1,sheet2,sheet3...) 我想要将它们全部添加到数组中,也许基于任何调用范围?现在我手动添加它们如下:

=query( 
{ 
INDIRECT("sheet1!$A:$V"); 
INDIRECT("sheet2!$A:$V"); 
INDIRECT("sheet3!$A:$V") };
"SELECT Col2, Col3, Col4, ...[etc]")

我想创建任何 "Settings" sheet 并将所有应该在数组中的 sheet 放在这里,如下所示:

=query( 
    { 
    get_all_sheets_names_from('settings!A1:A100'); // something like this
 };
    "SELECT Col2, Col3, Col4, ...[etc]")

可能吗?

我的尝试: https://docs.google.com/spreadsheets/d/1ZMzu6FuVyAJiWfNIHW87OW1Vpg_mM_QdtGs9nq9UXCU/edit#gid=0

我希望包含数据源的数组取自 G2:G 列。 C 列中的示例显示了如何手动完成此操作。但是,我正在寻找一种解决方案,以便在查询中无需执行任何操作,以便查询可以从 G2:G

中拖动一个包含数据源名称的数组

1) 我的想法

我认为在查询参数中使用"INDIRECT"是不可能的,因为"INDIRECT" return是一个单元格引用和参数{(); ()} 在查询中是固定对象。
"INDIRECT" 对完整查询也不可能,原因相同:查询不 return 对单元格的引用。

2) 资源有限

原理:案例1:查看G列第3行(第3个来源),如果为空则测试案例2,否则应用具有3个来源的公式。

情况 2:如果第二个源为空则转至情况 1,否则应用具有 2 个源的公式

情况 1:如果为空则显示 "no sources" 否则应用具有 1 个来源的公式

公式

注 1 ISBLANK(英语)替换 ESTVIDE(法语)!! 注 2:您可以使用 (G2="source1" 和 G3="source2"),
进行测试 但它适用于 G2="source3" 和 G3="source1"

=SI(ESTVIDE($G); SI(ESTVIDE($G); SI(ESTVIDE($G); "no source(s)";query({((INDIRECT("'"&G2&"'!A1:A5")))};"SELECT Col1")) ;query({(INDIRECT("'"&G2&"'!A1:A5"));(INDIRECT("'"&G3&"'!A1:A5"))};"SELECT Col1")) ;query({(INDIRECT("'"&G2&"'!A1:A5"));(INDIRECT("'"&G3&"'!A1:A5"));(INDIRECT("'"&G4&"'!A1:A5"))};"SELECT Col1"))

在线sheet

https://docs.google.com/spreadsheets/d/1sCwwFjpYKKzzAvVwmbMUWcmHSc1wY52XnHlFdT00A3U/edit?usp=sharing

限制

当然,这是一个最多只有 3 个来源的公式! 如果来源更多,它将变得又大又丑...

脚本

宏是唯一的解决方案?

用宏解决

追加这个脚本, 它从 G2:G30 获取值源值(你需要更多...把 G100..)
它创建公式并将其放在 H2
它在每个源中读取最多 50 个值(请参阅源代码中的 A1:A50) 不难理解,

注意:使用 GSheet 管理宏是另一个问题,如果您需要建议,请 post 发表评论。

link 生活 sheet : https://docs.google.com/spreadsheets/d/14XaR-UsADUpCUCVWqeg0zCbfGy3CCvnwVxUhozjYocc/edit?usp=sharing

function formula6() {
  var spreadsheet = SpreadsheetApp.getActive();

  var values=spreadsheet.getRange('G2:G30').getValues();

  var acSources="{";
  for (var i = 0; (i < values.length) && (values[i]!=""); i++) {
    if (i>0) {  acSources+=";" }
    acSources=acSources+'INDIRECT("'+values[i]+'!A1:A50")';
  }
  acSources=acSources+"}";

  var formula='query('+acSources+';"SELECT Col1")';

  spreadsheet.getRange('H2').activate();
  spreadsheet.getCurrentCell().setFormula('='+formula);

};

INDIRECT 函数复制粘贴到 Google 工作表中的人完全没有理解它的潜力,因此他们零努力地改进它并涵盖了在其中至关重要的明显逻辑这个数组时代。

换句话说,INDIRECT 不能摄入多个数组:

=INDIRECT("Sheet1!A:B"; "Sheet2!A:B")

也不会将数组字符串转换为活动引用,这意味着任何连接尝试也是徒劳的:

=INDIRECT(MasterSheet!A1:A10)
————————————————————————————————————————————————————————————————————————————————————
=INDIRECT("{Sheet1!A:B; Sheet2!A:B}")
————————————————————————————————————————————————————————————————————————————————————
={INDIRECT("Sheet1!A:B"; "Sheet2!A:B")}
————————————————————————————————————————————————————————————————————————————————————
=INDIRECT("{INDIRECT("Sheet1!A:B"); INDIRECT("Sheet2!A:B")}")

唯一可能的方法是对每个范围的每一端使用 INDIRECT,例如:

={INDIRECT("Sheet1!A:B"); INDIRECT("Sheet2!A:B")}

这意味着如果只有 sheets/tabs 的一部分存在,那么你能做的最好的事情就是像这样 预编程 你的数组(让我们有一个场景总共 4 个中只创建了 2 个 sheet):

=QUERY(
 {IFERROR(INDIRECT("Sheet1!A1:B5"), {"",""}); 
  IFERROR(INDIRECT("Sheet2!A1:B5"), {"",""}); 
  IFERROR(INDIRECT("Sheet3!A1:B5"), {"",""}); 
  IFERROR(INDIRECT("Sheet4!A1:B5"), {"",""})}, 
 "where Col1 is not null", 0)

所以,即使 sheet 名称是可预测的(并非总是如此),像这样预编程 100 多个 sheet 也会很痛苦(即使有各种偷偷摸摸的方法如何在 30 秒内写出这样的公式)


另一种方法是使用脚本转换字符串并将其作为公式注入

A1 将是创建一个看起来像真实公式的字符串的公式:

=ARRAYFORMULA("=QUERY({"&TEXTJOIN("; "; 1; 
 FILTER(SNAME(1); SNAME(1)<>SNAME(0))&"!A1:A20")&"}; ""where Col1 is not null""; 0)")

然后此脚本将从 A1 单元格中获取字符串并将其作为有效公式粘贴到 A2 单元格中:

function onEdit() { 
var sheet = SpreadsheetApp.getActive().getSheetByName('query');  // MASTER SHEET NAME
var src = sheet.getRange("A1");                                  // COPY STRING FROM
var str = src.getValue();
var cell = sheet.getRange("A2");                                 // PASTE AS FORMULA INTO 
cell.setFormula(str);
}
function SNAME(option) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet()
var thisSheet = sheet.getName(); 
if(option === 0){                  // ACTIVE SHEET NAME =SNAME(0)
return thisSheet;
}else if(option === 1){            // ALL SHEET NAMES   =SNAME(1)
var sheetList = [];
ss.getSheets().forEach(function(val){
   sheetList.push(val.getName())
});
return sheetList;
}else if(option === 2){            // SPREADSHEET NAME  =SNAME(2)
return ss.getName();

}else{
return "#N/A";                     // ERROR MESSAGE
};
}

当然,脚本可以更改为 onOpen 触发器或自定义名称从自定义菜单或通过按钮触发(但是不能直接将自定义函数用作公式)

如果添加了新的 sheet,这将满足您不通过添加引用来编辑公式的所有需求。唯一的缺点是重新计算 sheet 名称脚本...为此,您需要拆除 A1 公式,例如在前导 = 之前添加 ' 按回车键,然后将其删除修正公式

spreadsheet demo