如何显示来自其他工作表的信息,特定于单元格中的文本

How to display info from other sheets, specific to text in cells

我们公司在不同的物业维修电器,我想建立一个数据库来搜索每个电器在特定物业及其特定 apt/units 中的信息,我创建了一个表格来开始这个过程,但我需要一些复杂编码方面的帮助。

我首先为 属性 创建了一个框,然后我创建了一个“Apt/Unit”框。这个想法是当我 select 一个 属性 时,与 属性 相关的单位显示在 Apt/Unit 框中的 dropdown/type 可搜索列表中。

然后我创建了一个“设备类型”框。这个想法是,当“Apt/Unit”被 select 编辑时,它将显示与特定“Apt/Unit”相关的设备的 dropdown/type 可搜索列表。

然后我为设备的信息(品牌、型号、序列号和颜色)创建了框,这有点不言自明 - 一旦设备类型被 selected,它将显示该设备每个盒子的相应信息。

这是 link 到 Google sheet:https://docs.google.com/spreadsheets/d/1JZhEYjk5xVN3uOc_Ucb8HFr6d96XQ2Q_ehAd-d_o0ME/edit?usp=sharing

感谢任何帮助!

只是为了好玩,我做到了。但这太过分了:

// global variables
var SS = SpreadsheetApp.getActiveSpreadsheet();
var SHEET_USERFACE = SS.getSheetByName('Userface');
var SHEET_DATA = SS.getSheetByName('Data');

function onLoad() { reset() }

function onEdit(e) {
  if (e.range.getSheet().getName() != 'Userface') return;
  if (e.range.columnStart != 3) return;
  if (![9,11,13,15,17,19,21].includes(e.range.rowStart)) return;
  e.source.toast('Please, wait...');
  set_filter(e.range.offset(0,-1).getValue(), e.value);
  set_all_menus();
  e.source.toast('The sheet has been updated');
}

function reset() {
  SS.toast('Please wait...');
  try { SHEET_DATA.getFilter().remove() } catch(e) {}
  SHEET_USERFACE.getRange('c9:c21').clearContent().clearDataValidations();
  set_all_menus();
  SS.toast('The sheet has been updated');
}

function set_all_menus() {
  var data = SHEET_DATA.getDataRange().getDisplayValues().filter((_,i) => !SHEET_DATA.isRowHiddenByFilter(i+1));

  set_menu(data, 'b9',  'c9');
  set_menu(data, 'b11', 'c11');
  set_menu(data, 'b13', 'c13');
  set_menu(data, 'b15', 'c15');
  set_menu(data, 'b17', 'c17');
  set_menu(data, 'b19', 'c19');
  set_menu(data, 'b21', 'c21');
}

function set_menu(data, title, cell) {
  var menu_title = SHEET_USERFACE.getRange(title).getValue();
  var menu_cell = SHEET_USERFACE.getRange(cell);
  var col_index = data[0].indexOf(menu_title);
  var menu_list = [...new Set([...data.map(e => e[col_index])])].slice(1);
  var menu_rule = SpreadsheetApp.newDataValidation().requireValueInList(menu_list).build();
  menu_cell.setDataValidation(menu_rule);
}

function set_filter(column_title, value) {

  // get all the data and col index
  var [header, ...data] = SHEET_DATA.getDataRange().getValues();
  var col_index = header.indexOf(column_title);

  // unhide all values of the given column
  var clear = SpreadsheetApp.newFilterCriteria().setHiddenValues([]).build();
  var range = SHEET_DATA.getDataRange();
  var filter = range.getFilter() || range.createFilter()
  filter.setColumnFilterCriteria(col_index+1, clear);

  // get the values to hide
  var col_data = data.map(e => e[col_index]);
  var filtered = col_data.filter( (e, i) => e != value && SHEET_DATA.isRowHiddenByFilter(i+1) );
  var to_hide = col_data.filter( e => e != value );
  var hidden = [...new Set([...filtered, ...to_hide])];
  
  // hide the values with the filter
  var criteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(hidden).build();
  var range = SHEET_DATA.getDataRange();
  var filter = range.getFilter() || range.createFilter()
  filter.setColumnFilterCriteria(col_index+1, criteria);
}

Here is the sheet.

运行速度很慢。我建议改为使用本机过滤器。基本上,脚本分别打开和关闭下拉菜单的过滤器和更改数据验证。


更新

这里是脚本的另一个版本。它工作得更快,但它使用 'helper sheet' 来存储临时数据(过滤后的 table)。如果需要,您可以隐藏 'helper sheet'。

// global variables
var SS = SpreadsheetApp.getActiveSpreadsheet();
var SHEET_USERFACE = SS.getSheetByName('Userface');
var SHEET_DATA = SS.getSheetByName('Data');
var SHEET_HELPER = SS.getSheetByName('Helper'); // the hidden sheet with temp data
var PROPERTY_LIST = [...new Set(SHEET_DATA.getRange('a2:a').getValues().flat())]; // 'Property' list
var DATA_OBJ = {}; 

function onLoad() { reset() }

function onEdit(e) {
  var {range, source, value} = e;

  if (range.getSheet().getName() != 'Userface') return;
  if (range.columnStart != 3) return;
  if (![9,11,13,15,17,19,21].includes(range.rowStart)) return;

  source.toast('Please, wait...');

  // reset whenever the first menu is changing
  if (range.rowStart == 9) {
    reset();
    source.getRange('c9').setValue(value);
  }

  var col_header = range.offset(0,-1).getValue();

  update_sheet_helper(col_header, value);
  update_all_dropdown_menus();
  
  source.toast('The sheet has been updated');
}

function reset() {
  SS.toast('Please wait...');

  // copy data from SHEET_DATA to SHEET_HELPER
  SHEET_USERFACE.getRange('c9:c21').clearContent().clearDataValidations();
  SHEET_DATA.getDataRange().copyTo(SHEET_HELPER.clearContents().getRange(1,1));

  update_data_obj();
  update_all_dropdown_menus();

  SS.toast('The sheet has been updated');
}

// make DATA_OBJECT from SHEET_HELPER
function update_data_obj() {
  DATA_OBJ = {};
  var [header, ...data] = SHEET_HELPER.getDataRange().getValues();
  for (let i in header) DATA_OBJ[header[i]] = data.map(e => e[i]);
  DATA_OBJ['Property'] = PROPERTY_LIST; // let 'Property' list will be full always
}

// remove from SHEET_DATA_HELPER all the rows
// that have no given value in column with given title
function update_sheet_helper(col_title, value) {
  var [header, ...data] = SHEET_HELPER.getDataRange().getValues();
  var col_index = header.indexOf(col_title);
  data = data.filter(k => k[col_index] == value);
  var table = [header, ...data];
  SHEET_HELPER.clearContents().getRange(1,1,table.length, table[0].length).setValues(table);
  update_data_obj();
}

function update_all_dropdown_menus() {
  SHEET_USERFACE.getRange('b9:c21').getValues().forEach((row,i) => {
      if (row[0] != '') set_data_validation(DATA_OBJ[row[0]], 'c' + (i+9));
    });

  function set_data_validation(data, cell_address) {
    var menu_list = [...new Set([...data])]; // remove duplicates from the array
    var menu_rule = SpreadsheetApp.newDataValidation().requireValueInList(menu_list).build();
    var cell_range = SHEET_USERFACE.getRange(cell_address)
    cell_range.setDataValidation(menu_rule);
    if (menu_list.length == 1) cell_range.setValue(menu_list[0]);
  }
}

The sheet is here.

这是脚本的第三个变体:

// global variables
var SS = SpreadsheetApp.getActiveSpreadsheet();
var SHEET_USERFACE = SS.getSheetByName('Userface');
var SHEET_DATA = SS.getSheetByName('Data');

function onLoad() { reset() }

function reset() {
  SS.toast('Please wait...');

  SHEET_USERFACE.getRange('c9:c21').clearContent();
  SHEET_USERFACE.getRange('c9:c13').clearDataValidations();

  var obj = make_obj_from_data();
  update_menu_prop(obj);
  update_menu_unit(obj);
  update_menu_type(obj);

  SS.toast('The sheet has been reset');
}

function onEdit(e) {
  if (e.range.getSheet().getName() != 'Userface') return;
  if (e.range.columnStart != 3) return;

  // Property menu
  if (e.range.rowStart == 9) {
    e.source.toast('Please, wait...');
    SHEET_USERFACE.getRange('c11:c21').clearContent();
    SHEET_USERFACE.getRange('c11:c13').clearDataValidations();
    var obj = make_obj_from_data();
    update_menu_unit(obj);
    update_menu_type(obj);
    e.source.toast('The sheet has been updated');
  }

  // Apt/Unit menu
  if (e.range.rowStart == 11) {
    e.source.toast('Please, wait...');
    SHEET_USERFACE.getRange('c13:c21').clearContent();
    SHEET_USERFACE.getRange('c13').clearDataValidations();
    var obj = make_obj_from_data();
    update_menu_type(obj);
    e.source.toast('The sheet has been updated');
  }

  // Applicance type menu
  if (e.range.rowStart == 13) {
    e.source.toast('Please, wait...');
    SHEET_USERFACE.getRange('c15:c21').clearContent();
    var obj = make_obj_from_data();
    update_brand_model_serial_color(obj);
    e.source.toast('The sheet has been updated');
  }
  
}

function make_obj_from_data() {
  var data = SHEET_DATA.getDataRange().getValues().slice(1);
  var obj = {};

  for (let row of data) {
    var [prop, unit, type, ...etc] = row;
    try { 
      obj[prop][unit][type] = etc;
    }
    catch(e) { 
      try {
        obj[prop][unit] = {}; obj[prop][unit][type] = etc;
      }
      catch(e) {
        obj[prop] = {}; obj[prop][unit] = {}; obj[prop][unit][type] = etc;
      }
    }
  }

  return obj;
}

function update_menu_prop(obj) {
  var cell = SHEET_USERFACE.getRange('c9');
  try {
    var list = Object.keys(obj);
    set_data_validation(cell, list);
  } catch(e) {
    console.log('update_menu_prop(obj)');
    console.log(e);
  } 
}

function update_menu_unit(obj) {
  var prop = SHEET_USERFACE.getRange('c9').getValue();
  var cell = SHEET_USERFACE.getRange('c11');
  try {
    var list = Object.keys(obj[prop]);
    set_data_validation(cell, list);
  } catch(e) {
    console.log('update_menu_unit(obj)');
    console.log(e);
  }
}

function update_menu_type(obj) {
  var prop = SHEET_USERFACE.getRange('c9').getValue();
  var unit = SHEET_USERFACE.getRange('c11').getValue();
  var cell = SHEET_USERFACE.getRange('c13');
  try {
    var list = Object.keys(obj[prop][unit]);
    set_data_validation(cell, list);
    if (list.length == 1) update_brand_model_serial_color(obj)
  } catch(e) {
    console.log('update_menu_type(obj)');
    console.log(e);
  }
}

function update_brand_model_serial_color(obj) {
  var [prop,,unit,,type] = SHEET_USERFACE.getRange('c9:c13').getValues();
  try {
    var [brand, model, serial, color] = obj[prop][unit][type];
    var arr = [[brand],[''],[model],[''],[serial],[''],[color]];
    SHEET_USERFACE.getRange('c15:c21').setValues(arr);
  } catch(e) {
    console.log('update_brand_model_serial_color(obj)');
    console.log(e);
  }
}

function set_data_validation(cell, list) {
  var rule = SpreadsheetApp.newDataValidation().requireValueInList(list).build();
  cell.setDataValidation(rule);
  // put the value in the cell if there is just one element in the list
  if (list.length == 1) cell.setValue(list[0]);
}

Here is my sheet.

它的工作方式与任何类似的界面一样。您 select 第一个菜单,它更改了第二个菜单的数据验证并清除了第三个菜单。然后你 select 第二个菜单,它改变了第三个。只要您更改第三个菜单,它就会填充其余字段。

由于您只使用了三个菜单,而且它们应该逐步更改,所以我决定 'hardcode' 它们。这不是最佳做法,可能会出现问题 if/when 您决定更改功能。但是对于这种特殊情况,我认为 'hardcoding' 是可以原谅的。运行速度比较快,代码也比较可读。

non-scripted 解决方案:

=IFERROR({INDEX(IFERROR(Data!A1:G1/0)); Data!A1:G1; QUERY({Data!A2:G}, "where 1=1 "&
 IF(C10="",,"and lower(Col1) contains '"&LOWER(C10)&"'")&
 IF(C12="",,"and Col2 = "&C12)&
 IF(C14="",,"and lower(Col3) contains '"&LOWER(C14)&"'")&
 IF(C16="",,"and lower(Col4) contains '"&LOWER(C16)&"'")&
 IF(C18="",,"and lower(Col5) contains '"&LOWER(C18)&"'")&
 IF(C20="",,"and lower(Col6) contains '"&LOWER(C20)&"'")&
 IF(C22="",,"and lower(Col7) contains '"&LOWER(C22)&"'"), 0)}, {"";"no data"})

demo sheet