Sử dụng Truy vấn với các tiêu đề cột thay vì các chữ cái cột


7

Tôi có một công thức mà tôi sử dụng để tự động lấy ký tự cột cho mảng 1 chiều là các tiêu đề cột của trang tính. Để sử dụng QUERY () với tên cột thay vì chữ cái.

SUBSTITUTE(ADDRESS(1,MATCH("Weight", Headers, 0),4), "1", "")

Cú pháp chiếm một chút dung lượng và có thể gây khó khăn cho mắt khi các truy vấn trở nên dài. Một ví dụ:

=QUERY(A3:F13, "select "&SUBSTITUTE(ADDRESS(1,MATCH("Type", Headers, 0),4), "1", "")&" where ("&SUBSTITUTE(ADDRESS(1,MATCH("Version", Headers, 0),4), "1", "")&" = 'Version 1') and ("&SUBSTITUTE(ADDRESS(1,MATCH("Type", Headers, 0),4), "1", "")&" <> 'Type')")

Có giống như

=QUERY(A3:F13, "select E where (A = 'Version 1') and (E <> 'Type')")

Với lợi thế là luôn chọn hàng tôi muốn bất kể họ đang ở thứ tự nào.

Có thể tạo một chức năng hoạt động như sau mà không cần tạo lại bánh xe trong tập lệnh ứng dụng không?:

GetHeaders(range, string)

=QUERY(A3:F13, "select "&GetHeader(Headers, "Type")&" where ("&GetHeader(Headers, "Version")&" = 'Version 1') and ("&GetHeader(Headers, "Type")&" <> 'Type')")

Như đã được giải thích bởi @N normal Human trong một nhận xét trong câu trả lời của mình, cách duy nhất để tạo một chức năng tùy chỉnh là sử dụng Apps Script. Nếu bạn yêu cầu câu trả lời mà không sử dụng nó, "tạo một hàm" nên được sắp xếp lại (nghĩa là "tạo công thức") và đề cập đến việc sử dụng các hàm tùy chỉnh không mong muốn.
Rubén

Câu trả lời:


4

Không có tập lệnh ứng dụng

Người ta không thể tạo một chức năng mới mà không có Apps Script. Cách duy nhất để hợp lý hóa quy trình là đặt nhiều ô ở đâu đó và tham chiếu các ô đó.

Ví dụ: dưới mỗi tiêu đề, chẳng hạn như 'Trọng lượng', hãy nhập lệnh

=regexextract(address(1, column()), "[A-Z]+")

Điều này sẽ đặt (các) chữ cái cột dưới tiêu đề. Bao gồm các hàng với các chữ cái trong phạm vi tiêu đề được đặt tên. Trong chuỗi truy vấn, sử dụng

hlookup("Weight", Headers, 2, 0)

cái nào dễ nhìn hơn

SUBSTITUTE(ADDRESS(1,MATCH("Weight", Headers, 0),4), "1", "")

Với tập lệnh ứng dụng

Truyền một phạm vi (được đặt tên hoặc cách khác) vào một hàm tùy chỉnh sẽ chuyển vào các giá trị , không có thông tin về vị trí của chúng trong trang tính. Nhưng tôi đã tìm thấy một giải pháp: suy ra vị trí của các tiêu đề từ đối số đầu tiên query. Không cần bao gồm "Tiêu đề", bản thân nó đã lặp đi lặp lại.

Phiên bản 1: các tiêu đề được bao gồm trong phạm vi truy vấn

Tôi thích bao gồm các hàng tiêu đề trong phạm vi được truyền cho truy vấn và chỉ định số lượng hàng tiêu đề làm đối số thứ 3 của query. Điều này tránh việc giải thích sai dữ liệu là tiêu đề hoặc ngược lại. Ví dụ:

=QUERY(A1:F13, "select "&GetHeader("Type")&" where ("&GetHeader("Version")&" = 'Version 1') and ("&GetHeader("Type")&" <> 'Type')", 2) 

Đây là chức năng tùy chỉnh để sử dụng với truy vấn trên:

function getHeader(name) {
  var sheet = SpreadsheetApp.getActiveSheet();
  var formula = SpreadsheetApp.getActiveRange().getFormula();
  var args = formula.match(/\w+:\w+(?=[ ,])/);
  var range = sheet.getRange(args[0]);
  var firstRow = range.offset(0, 0, 1, range.getWidth());
  var headers = firstRow.getValues();
  for (var i = 0; i < headers[0].length; i++) {
    if (headers[0][i] == name) {
      var notation = range.getCell(1, i+1).getA1Notation();
      var column = notation.replace(/\d/, '');
      return column;
    }
  }
  return 'Not found';
}

Hàm lấy công thức từ ô mà nó được gọi. Nó trích xuất đối số phạm vi đầu tiên của công thức với một biểu thức chính quy. Sau đó, nó nhìn qua hàng đầu tiên của phạm vi này , giả sử đó là hàng tiêu đề, để tìm kiếm chuỗi đã cho. Nó nhận được ký hiệu A1 của ô với chuỗi, loại bỏ phần hàng của nó và trả về kết quả.

Phiên bản 2: các tiêu đề được lấy từ Hàng 1

Một phiên bản thay thế, trong đó các tiêu đề được lấy từ hàng đầu tiên của trang tính, bất kể các hàng trong đối số truy vấn. Chỉ cần thay thế

  var firstRow = range.offset(0, 0, 1, range.getWidth());

với

  var firstRow = sheet.getRange(1, range.getColumn(), 1, range.getWidth());

Với phiên bản này, bạn có thể sử dụng

=QUERY(A3:F13, "select "&GetHeader("Type")&" where ("&GetHeader("Version")&" = 'Version 1') and ("&GetHeader("Type")&" <> 'Type')")  

Cảm ơn con người bình thường! Mặc dù vậy, tôi muốn tránh sử dụng Apps Script vì các chức năng tùy chỉnh có xu hướng chỉ hoạt động không liên tục khi được sử dụng hàng loạt. Tôi cần một cái gì đó hoạt động mọi lúc và theo kinh nghiệm của tôi, các chức năng tùy chỉnh không hoạt động mọi lúc ( Loading...Vấn đề vĩnh viễn có thể giải quyết được xóa và dán lại chức năng).
Douglas Gaskell

1
Bạn đã yêu cầu "tạo một chức năng" .... sử dụng Apps Script là cách duy nhất để tạo một chức năng mới. Mặt khác, không có gì ngoài việc sao chép cùng một sự kết hợp của các chức năng tích hợp xung quanh. Tôi hiểu mối quan tâm về hiệu suất, nhưng thường thì số lượng truy vấn không lớn hoặc bạn có vấn đề về hiệu suất liên quan đến chính các truy vấn.

1
Điều đó nói rằng, tôi đã thêm đề nghị của tôi để giao dịch mà không có Script.

0

Tôi thực sự thích câu trả lời được cung cấp bởi user79865. Nếu bạn muốn sử dụng nó và có ngôn ngữ khác với Hoa Kỳ (như tiếng Ba Lan của tôi), bạn có thể có dấu phân cách khác nhau cho các đối số chức năng trong Trang tính. Và thay vì:

=QUERY(A3:F13, "select "&GetHeader("Type")&" where ("&GetHeader("Version")&" = 'Version 1') and ("&GetHeader("Type")&" <> 'Type')", 2)

bạn có thể có ( ;thay thế ,):

=QUERY(A3:F13; "select "&GetHeader("Type")&" where ("&GetHeader("Version")&" = 'Version 1') and ("&GetHeader("Type")&" <> 'Type')"; 2)

Trong trường hợp như vậy, regex trong chức năng (Phiên bản 1), dòng 4, nên được thay đổi từ:

var args = formula.match(/\w+:\w+(?=[ ,])/);

đến:

var args = formula.match(/\w+:\w+(?=[ ;])/);


Và cuối cùng nếu dữ liệu của bạn nằm trong trang tính riêng (nhưng trong cùng một bảng tính), bạn có thể sửa đổi biểu thức chính quy để tìm tên trang tính và sử dụng nó để tìm kiếm tên cột:

function getHeader( name ) {
  var sheet = SpreadsheetApp.getActiveSheet();
  var formula = SpreadsheetApp.getActiveRange().getFormula();
  var args = formula.match(/\((\'*(.+(?=[!']))\'*!)*(\w+:\w+(?=[ ;]))/); // 1: "'sheet name'!", 2:"sheet name", 3:"A1:D100"
  if( args[2] ) 
    sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(args[2]);
  var range = sheet.getRange(args[3]);
  var firstRow = range.offset(0, 0, 1, range.getWidth());
  var headers = firstRow.getValues();
  for (var i = 0; i < headers[0].length; i++) {
    if (headers[0][i] == name) {
      var notation = range.getCell(1, i+1).getA1Notation();
      var column = notation.replace(/\d/, '');
      return column;
    }
  }
  return 'Not found';
}


Tôi muốn thêm bình luận, nhưng là một thành viên mới làm quen, tôi không thể bình luận ...

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.