Google Sheets 查询 - 动态构建引用的数组源

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

我的电子表格中有很多工作表(sheet1、sheet2、sheet3...),我想将它们全部添加到数组中,也许基于任何调用范围?现在我手动添加它们,如下所示:

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

我想创建任何“设置”表,并将所有应排列在数组中的表放在这里,如下所示:

=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 中的数据源名称的数组

arrays google-sheets google-sheets-formula array-formulas google-sheets-query
3个回答
2
投票

1)我的想法

我认为不可能在查询参数中使用“INDIRECT”,因为“INDIRECT”返回单元格引用和参数 {();查询中的 ()} 是固定对象。
出于同样的原因,完整查询上的“间接”也是不可能的:查询不会返回单元格上的引用。

2) 解决方案有限

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

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

情况 1:如果为空则显示“无来源”,否则应用具有 1 个来源的公式

公式

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

=SI(ESTVIDE($G$4); SI(ESTVIDE($G$3); SI(ESTVIDE($G$1); "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"))

在线表格

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

限制

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

脚本

宏是唯一的解决方案吗?

用宏解决

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

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

链接到实时表: 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);

};

2
投票

INDIRECT
函数复制粘贴到 Google Sheets 中的家伙完全无法理解它的潜力,因此他们不遗余力地改进它并涵盖在这个数组时代至关重要的明显逻辑。

换句话说,

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

这意味着,如果只有部分工作表/选项卡存在,您能做的最好的事情就是像这样预编程您的数组(让我们假设一个场景,总共 4 个工作表中只创建了 2 个工作表):

=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)

所以,即使工作表名称是可预测的(并不总是如此),像这样预编程 100 多个工作表也会很痛苦(即使有各种偷偷摸摸的方法如何在 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
};
}

0

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

这将满足您在添加新工作表时无需通过添加引用来编辑公式的所有需求。唯一的缺点是重新计算工作表名称脚本...为此,您需要拆除 A1 公式,例如在前导

'
之前添加
=
按 Enter 键,然后将其删除以修复公式

电子表格演示


0
投票

通过添加新功能,我们可以轻松做到这一点:

=REDUCE(HSTACK(,,), INDEX(A2:A3&TEXT(B2:B3, " mm/dd")), 
 LAMBDA(a, b, {a; INDIRECT(b&"!A1:C5")}))

enter image description here

解决尚不存在的工作表的问题:

enter image description here

我们可以添加 IFERROR,例如:

=REDUCE(HSTACK(,,), INDEX(A2:A5&TEXT(B2:B5, " mm/dd")), 
 LAMBDA(a, b, {a; IFERROR(INDIRECT(b&"!A1:C5"), HSTACK(,,))}))

enter image description here

为了不重复标题,我们可以这样做:

=REDUCE({"Date", "Test Name", "Test Data"}, INDEX(A2:A5&TEXT(B2:B5, " mm/dd")), 
 LAMBDA(a, b, {a; IFERROR(INDIRECT(b&"!A2:C5"), HSTACK(,,))}))

enter image description here

我们可以使用:

代替A2:B5
=SEQUENCE(5, 1, "2019-01-06", 7)

enter image description here

直接就是:

=REDUCE({"Date", "Test Name", "Test Data"}, 
 INDEX("week of "&TEXT(SEQUENCE(5, 1, "2019-01-06", 7), "mm/dd")), 
 LAMBDA(a, b, {a; IFERROR(INDIRECT(b&"!A2:C5"), HSTACK(,,))}))

enter image description here

并使用 OP 查询:

=QUERY(REDUCE({"Date", "Test Name", "Test Data"}, 
 INDEX("week of "&TEXT(SEQUENCE(5, 1, "2019-01-06", 7), "mm/dd")), 
 LAMBDA(a, b, {a; IFERROR(INDIRECT(b&"!A2:C"), HSTACK(,,))})), 
 "where Col3 = 'RP' order by Col2", 1)

enter image description here

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