【问题标题】:Joining tables in queries google sheets在查询谷歌表格中加入表格
【发布时间】:2021-01-06 21:06:01
【问题描述】:

基本上我有两个看起来像这样的谷歌表格:

人们可以在其中输入电子邮件并选择他们正在使用的 foo 类型的表格

email foo
example@email.com This Foo

然后是另一个包含 foo 信息的表

foo name foo type foo boolean1 foo boolean2
This Foo String True True
That Foo Number False True
Other Foo String False False

在单独的表格中,我希望有一个类似于仪表板的视图,其中我会计算各种事物,例如人数、每种类型的 Foo 有多少等

我遇到麻烦的地方是弄清楚如何提取诸如“选择 String foos 的人数”之类的内容

喜欢,基本上我想要相当于(在 sql 中)的 google-query

SELECT COUNT(p.*) FROM people p JOIN info i on p.foo = i.foo_name GROUP BY i.foo_type WHERE i.foo_type = 'String'

我要找的是这样的表格:

Data Count
Active Roster 4
String 3
Number 1

【问题讨论】:

  • 分享您的工作表副本以及所需结果的示例

标签: google-sheets google-query-language


【解决方案1】:

我还看到了许多具有复杂公式的解决方案,使用 VLOOKUPINDEXMATCH 等。

我决定编写一个用户函数来组合表,或者按照我的说法,对数据库进行非规范化。我编写了函数DENORMALIZE() 来支持INNERLEFTRIGHTFULL 加入。通过嵌套函数调用,理论上可以加入无限的表。

DENORMALIZE(range1, range2, primaryKey, foreignKey, [joinType])

参数:

  • range1,主表为命名范围、a1Notation 或数组
  • range2,相关表为命名范围、a1Notation 或数组
  • primaryKey,主表唯一标识,列以“1”开头
  • foreignKey,关联表中加入主表的key,列以“1”开头
  • joinType,连接类型,“Inner”、“Left”、“Right”、“Full”,可选,默认为“Inner”,不区分大小写

返回:二维数组的结果

结果集示例:

=QUERY(denormalize("Employees","Orders",1,3), "SELECT * WHERE Col2 = 'Davolio' AND Col8=2", FALSE)
EmpID LastName FirstName OrderID CustomerID EmpID OrderDate ShipperID
1 Davolio Nancy 10285 63 1 8/20/1996 2
1 Davolio Nancy 10292 81 1 8/28/1996 2
1 Davolio Nancy 10304 80 1 9/12/1996 2

其他例子:

=denormalize("Employees","Orders",1,3)
=denormalize("Employees","Orders",1,3,"full")
=QUERY(denormalize("Employees","Orders",1,3,"left"), "SELECT * ", FALSE)
=QUERY(denormalize("Employees","Orders",1,3), "SELECT * WHERE Col2 = 'Davolio'", FALSE)
=QUERY(denormalize("Employees","Orders",1,3), "SELECT * WHERE Col2 = 'Davolio' AND Col8=2", FALSE)
=denormalize("Orders","OrderDetails",1,2)
// multiple joins 
=denormalize("Employees",denormalize("Orders","OrderDetails",1,2),1,3)
=QUERY(denormalize("Employees",denormalize("Orders","OrderDetails",1,2),1,3), "SELECT *", FALSE)
=denormalize(denormalize("Employees","Orders",1,3),"OrderDetails",1,2)
=QUERY(denormalize("Employees",denormalize("Orders","OrderDetails",1,2),1,3), "SELECT *", FALSE)
=QUERY(denormalize(denormalize("Employees","Orders",1,3),"OrderDetails",4,2), "SELECT *", FALSE)

function denormalize(range1, range2, primaryKey, foreignKey, joinType) {
  var i = 0;
  var j = 0;
  var index = -1;
  var lFound = false;
  var aDenorm = [];
  var hashtable = [];
  var aRange1 = "";
  var aRange2 = "";
  joinType = DefaultTo(joinType, "INNER").toUpperCase();
  // the 6 lines below are used for debugging
  //range1 = "Employees";
  //range1 = "Employees!A2:C12";
  //range2 = "Orders";
  //primaryKey = 1;
  //foreignKey = 3;
  //joinType = "LEFT";
  // Sheets starts numbering columns starting with "1", arrays are zero-based
  primaryKey -= 1;
  foreignKey -= 1;
  // check if range is not an array
  if (typeof range1 !== 'object') {
    // Determine if range is a1Notation and load data into an array
    if (range1.indexOf(":") !== -1) {
      aRange1 = ss.getRange(range1).getValues();
    } else {
      aRange1 = ss.getRangeByName(range1).getValues();
    } 
  } else {
    aRange1 = range1;
  }
  
  if (typeof range2 !== 'object') {
    if (range2.indexOf(":") !== -1) {
      aRange2 = ss.getRange(range2).getValues();
    } else {
      aRange2 = ss.getRangeByName(range2).getValues();
    }
  } else {
    aRange2 = range2;
  }
  
  // make similar structured temp arrays with NULL elements
  var tArray1 = MakeArray(aRange1[0].length);
  var tArray2 = MakeArray(aRange2[0].length);
  var lenRange1 = aRange1.length;
  var lenRange2 = aRange2.length;
  hashtable = getHT(aRange1, lenRange1, primaryKey);
  for(i = 0; i < lenRange2; i++)  {
    index = hashtable.indexOf(aRange2[i][foreignKey]);
    if (index !== -1) {
      aDenorm.push(aRange1[index].concat(aRange2[i]));
    }
  }
  // add left and full no matches
  if (joinType == "LEFT" || joinType == "FULL") {
    for(i = 0; i < lenRange1; i++)  {
      //index = aDenorm.indexOf(aRange1[i][primaryKey]);
      index = aScan(aDenorm, aRange1[i][primaryKey], primaryKey)
      if (index == -1) {
        aDenorm.push(aRange1[i].concat(tArray2));
      }
    }
  }
  // add right and full no matches
  if (joinType == "RIGHT" || joinType == "FULL") {
    for(i = 0; i < lenRange2; i++)  {
      index = aScan(aDenorm, aRange2[i][foreignKey], primaryKey)
      if (index == -1) {
        aDenorm.push(tArray1.concat(aRange2[i]));
      }
    }
  }
    return aDenorm;
}

function getHT(aRange, lenRange, key){
var aHashtable = [];
var i = 0;
for (i=0; i < lenRange; i++ ) {
  //aHashtable.push([aRange[i][key], i]);
  aHashtable.push(aRange[i][key]);
  }
return aHashtable;
}

function MakeArray(length) {
  var i = 0;
  var retArray = [];
  for (i=0; i < length; i++) {
    retArray.push("");
  }
  return retArray;
}

function DefaultTo(valueToCheck, valueToDefault) {
return typeof valueToCheck === "undefined" ? valueToDefault : valueToCheck;
}

// Search a multi-dimensional array for a value
function aScan(aValues, searchStr, searchCol) {
var retval = -1;
var i = 0;
var aLen   = aValues.length;
for (i = 0; i < aLen; i++) {
    if (aValues[i][searchCol] == searchStr) {
        retval = i;
        break;
    }
}
return retval;
}

您可以在此处复制包含数据和示例的 google 表格:

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

【讨论】:

    猜你喜欢
    • 2017-05-10
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 2021-12-06
    • 2021-05-20
    • 2016-05-18
    • 1970-01-01
    相关资源
    最近更新 更多