QUERY syntax for using a 'cell range reference' after the 'where' - google-query-language

I'm trying to use a cell range reference instead of static values. I Know how to select only one cell as writen below :
=QUERY('sheet 1'!1:468;"Select I where G = '"&B2&"'";-1)
... but not the whole range/column :
=QUERY('sheet 1'!1:468;"Select I where G = '"&B2:B99&"'";-1)
(with B2:B99 a query result from sheet 1)
...I keep getting a "Error" with the previous formula.
Thank you in advance,
Fred from France.

I would love to know the answer to this as well. I'd like to be able to have my query search for where based on 3 different cell requisites. I want to be able to build that on top of this question that I asked here:
My Question For A Google Query that selects from two values after a 'where' statement?
EDIT ANSWER:
Try this, Note the different quotes for the cell number reference.
=QUERY(A:T,"select A WHERE P = '"&S200&"' AND Q="&T200&"")

Related

Google Sheets Join information from two pages with query & vlookup

I know this has been asked several times, but I just can't seem to understand how to write the formula and I'm hoping to get some help.
Consider the following (example data) sheet:
https://docs.google.com/spreadsheets/d/1t_I_stZmZea4sfGPsCu6GtBhGJJT16CZ-sEu7JubFKc/edit?usp=sharing
First, note that I am importing data on "API Data" utilizing importJSON().
My goal is to combine (join) data from two sheets. I need "dataseries cloudcover" from 'API data' and "Dataseries example,Dataseries example 1,Dataseries example 2" from 'join'.
I gave it a shot here:
=query('API data'!A:L,"Select " & vlookup(B:B,'API data'!B:L,3,FALSE) & ",B,C,D,E,F,G,H,I,J,K,L")
Here is a SS of what I would like to see
This formula can help you to get that data:
Note: Just add the formula in A2
={ARRAYFORMULA(IF(ISBLANK('API data'!C2:C),"",ARRAYFORMULA(VLOOKUP('API data'!C2:C,'API data'!C2:D25,2)))),ARRAYFORMULA(IF(ISBLANK(Join!A2:A),"",ARRAYFORMULA(VLOOKUP(Join!A2:A,Join!A2:D25,{2,3,4},FALSE))))}
And it will look like this:
Edit:
Editing and adding more information about the use of this formula.
The formula is constructed with 2 different VLookUps, 1 for each tab, and they are merged using:
={First Array, Second Array}
The first Array is:
ARRAYFORMULA(IF(ISBLANK('API data'!K2:K),"",ARRAYFORMULA(VLOOKUP('API data'!K2:K,'API data'!K2:L25,2))))
The second Array is:
ARRAYFORMULA(IF(ISBLANK(Join!I2:I),"",ARRAYFORMULA(VLOOKUP(Join!I2:I,Join!I2:L25,{2,3,4},FALSE))))
The core part of the first array for this formula is:
ARRAYFORMULA(VLOOKUP('API data'!K2:K,'API data'!K2:L25,2))
The IF(IsBlank(column,"",Vlookup) will remove any empty value of the Array.
The same thing with the second Array, with the difference that I use an Array {2,3,4} to call all the columns in the second sheet.
Reference:
VLOOKUP function.
ARRAYFORMULA function.
IF function.
ISBLANK function.

Comparing two sentences and merge while removing duplicates

I plan on creating a remarks column within my sheet, and I want it to be such that whenever I update one side or the other, it will merge the remark and remove any duplicates within it.
Would appreciate if anyone has any inputs on this.
Example:
Remarks in the column of one google sheet:
-Friendly -Fun
Remarks in the other column of another google sheet :
-Friendly -Cheerful
So my google script will get the string in both columns, I would like to make the end result of the string to be :
-Friendly -Cheerful -Fun
Can you try like this to what I understand and see attached image as will
=Unique(Transpose(Split(TEXTJOIN(" ",True,B2,D2),"-",True)),False,False)

Match with concatenate across google sheets

I have this formula:
=IF(MATCH($A1&B$1,Sheet2!$A$1:$A$100&Sheet2!$B$1:$B$100,0), 1, 0)
I expect the formula in Sheet 1, Column C to produce all ones as in Excel but I only get a 1 when there is a row with a,b in Sheet 2:
https://docs.google.com/spreadsheets/d/1pyuWNNU7S07AC7d4zMvXft5pEz3AeAbeHcQp-wNsXpo/edit?usp=sharing
Why is this and is there a way around it that will also work in Excel?
Edit to clarify:
I want to be able to look up the value in two cells concatenated, e.g., $A1&B$1 and check if this matches any item in the list:
[Sheet2!$A$1&$B$1, Sheet2!$A$2&$B$2, Sheet2!$A$3&$B$3, ...]
Other details that may be important:
In my actual example, the columns I am looking at are not adjacent.
I would like the result to be compatible with as many spreadsheet programs as possible, especially Excel, Google Sheets and LibreOffice.
I will be writing the formula using openpyxl for Python.
Thanks, in advance.
I do not believe MATCH() is the appropriate function. There are lots of other options like vlookup(), index().
I like using the QUERY() function personally.
=QUERY(Sheet2!$A1:$B, "SELECT COUNT(A) WHERE A = '"&A1&"' AND B = '"&B1&"' LABEL COUNT(A) ''",0)
QUERY() shows #N/A when no results are found so we can wrap the above function accordingly
=IF(ISNA(query(Sheet2!$A1:$B, "SELECT COUNT(A) WHERE A = '"&A1&"' AND B = '"&B1&"' LABEL COUNT(A) ''",0)), "",query(Sheet2!$A1:$B, "SELECT COUNT(A) WHERE A = '"&A1&"' AND B = '"&B1&"' LABEL COUNT(A) ''",0))
the best way to use MATCH is making both parameters (search_key and range) expressed as brackets keys, the answer is:
=IF(MATCH({$A1}&{B$1},{Sheet2!$A$1:$A$100}&{Sheet2!$B$1:$B$100},0), 1, 0)
You MUST press Mayus + enter to asign the formula as an array

Tabulate JSON into Sheets

I've been trying to get a readable database of a JSON file from a URL.
I've used fastfedora's script on Github, https://github.com/fastfedora/google-docs/blob/master/scripts/ImportJSON/Code.gs, to import JSON from the URL to Sheets. I'm using the basic:
=TRANSPOSE(ImportJSON("https://rsbuddy.com/exchange/summary.json"))
I used transpose as it was easier to work with two long columns rather than two long rows.
The data that's been imported however, is very messy: https://docs.google.com/spreadsheets/d/1mKnRQmshbi1YFG9HHg7-mKlZZzpgDME6-eGjDJKzbRY/edit?usp=sharing. It's basically 1 long column of descriptive data, (name, id, price etc.) and another column of the variable (the actual name of the item and it's price in digits).
Is it possible to manipulate the resultant Sheets page so that the common factors in the first column can be lined up with the pseudo-table beside two initial columns? E.g. for the first item, the ID will be '2', the name will be 'Cannonball', the Sp will be '5' etc.
Thanks in advance. Do forgive me for my ignorance.
Example
Simple formula
I think, faster way to get IDs:
=QUERY(QUERY(A2:B,"select B where A <> '' offset 4"),"skipping 7")
and if you want Names:
=QUERY(QUERY(A2:B,"select B where A <> '' offset 1"),"skipping 7")
when you change offset from 0 to 6, you get different columns
outputs.
7 is the number of columns in Data.
The result is autocompleted column with Data.
Hard formula
Also possible to get the whole result with one formula:
paste =COUNTA(A:A) in cell E2
paste 7 in E3, this is the number of columns in Data
=E2/E3 in E4
And then in cell G2 or somewhere on right paste the formula:
=ArrayFormula(vlookup(if(COLUMN(OFFSET(A1,,,1,E3)),
(row(OFFSET(A1,,,E4))-1)*E3+COLUMN(OFFSET(A1,,,1,E3))),
{row(OFFSET(A1,,,E2)),OFFSET(B2,,,E2)},2,0))
It works slow, but gives the whole table.
or Script?
I've also tried to use script UDF function. Here's test formula:
=ConvertTo2D(TRANSPOSE(R3:R16),7)
where R3:R16 is small range which was splited into table with 7 columns. The script is pretty short:
function ConvertTo2D(Arr, index) {
var newArr = [];
while(Arr[0].length) newArr.push(Arr[0].splice(0,index));
return newArr;
}
Sounds good. But! It is ve-e-e-e-ery slow. So This solution is good only for quick test.
If the data is structured and every object will always have the same structure you can use a simple offset to do this:
=OFFSET($B$2,
(ROW($B2) - 2) * 7 +
COLUMN(D$1) - 4,
0)
Put that in D2 and drag to the right and down.
It is possible to immediately return the data in this fashion but for that you need to meddle with the script.

Selecting the last value of a column

I have a spreadsheet with some values in column G. Some cells are empty in between, and I need to get the last value from that column into another cell.
Something like:
=LAST(G2:G9999)
except that LAST isn't a function.
Similar answer to caligari's answer, but we can tidy it up by just specifying the full column range:
=INDEX(G2:G, COUNT(G2:G))
So this solution takes a string as its parameter. It finds how many rows are in the sheet. It gets all the values in the column specified. It loops through the values from the end to the beginning until it finds a value that is not an empty string. Finally it retunrs the value.
Script:
function lastValue(column) {
var lastRow = SpreadsheetApp.getActiveSheet().getMaxRows();
var values = SpreadsheetApp.getActiveSheet().getRange(column + "1:" + column + lastRow).getValues();
for (; values[lastRow - 1] == "" && lastRow > 0; lastRow--) {}
return values[lastRow - 1];
}
Usage:
=lastValue("G")
EDIT:
In response to the comment asking for the function to update automatically:
The best way I could find is to use this with the code above:
function onEdit(event) {
SpreadsheetApp.getActiveSheet().getRange("A1").setValue(lastValue("G"));
}
It would no longer be required to use the function in a cell like the Usage section states. Instead you are hard coding the cell you would like to update and the column you would like to track. It is possible that there is a more eloquent way to implement this (hopefully one that is not hard coded), but this is the best I could find for now.
Note that if you use the function in cell like stated earlier, it will update upon reload. Maybe there is a way to hook into onEdit() and force in cell functions to update. I just can't find it in the documentation.
Actually I found a simpler solution here:
http://www.google.com/support/forum/p/Google+Docs/thread?tid=20f1741a2e663bca&hl=en
It looks like this:
=FILTER( A10:A100 , ROW(A10:A100) =MAX( FILTER( ArrayFormula(ROW(A10:A100)) , NOT(ISBLANK(A10:A100)))))
LAST() function is not implemented at the moment in order to select the last cell within a range. However, following your example:
=LAST(G2:G9999)
we are able to obtain last cell using the couple of functions INDEX() and COUNT() in this way:
=INDEX(G2:G; COUNT(G2:G))
There is a live example at the spreedsheet where I have found (and solved) the same problem (sheet Orzamentos, cell I5). Note that it works perfectly even refering to other sheets within the document.
Summary:
=INDEX( FILTER( G2:G , NOT(ISBLANK(G2:G))) , COUNTA(G2:G) )
Details:
I've looked through and tried several answers, and here's what I've found:
The simplest solution (see Dohmoose' answer) works if there are no blanks:
=INDEX(G2:G; COUNT(G2:G))
If you have blanks, it fails.
You can handle one blank by just changing from COUNT to COUNTA (See user3280071's answer):
=INDEX(G2:G; COUNTA(G2:G))
However, this will fail for some combinations of blanks. (1 blank 1 blank 1 fails for me.)
The following code works (See Nader's answer and jason's comment):
=INDEX( FILTER( G2:G , NOT(ISBLANK(G2:G))) , ROWS( FILTER( G2:G , NOT(ISBLANK(G2:G)) ) ) )
but it requires thinking about whether you want to use COLUMNS or ROWS for a given range.
However, if COLUMNS is replaced with COUNT I seem to get a reliable, blank-proof implementation of LAST:
=INDEX( FILTER( G2:G , NOT(ISBLANK(G2:G))) , COUNT( FILTER( G2:G , NOT(ISBLANK(G2:G)) ) ) )
And since COUNTA has the filter built in, we can simplify further using
=INDEX( FILTER( G2:G , NOT(ISBLANK(G2:G))) , COUNTA(G2:G) )
This is somewhat simple, and correct. And you don't have to worry about whether to count rows or columns. And unlike script solutions, it automatically updates with changes to the spreadsheet.
And if you want to get the last value in a row, just change the data range:
=INDEX( FILTER( A2:2 , NOT(ISBLANK(A2:2))) , COUNTA(A2:2) )
In order to return the last value from a column of text values you need to use COUNTA, so you would need this formula:
=INDEX(G2:G; COUNTA(G2:G))
try this:
=INDIRECT("B"&arrayformula(max((B3:B<>"")*row(B3:B))))
Suppose the column in which you are looking for the last value is B.
And yes, it works with blanks.
This one works for me:
=INDEX(I:I;MAX((I:I<>"")*(ROW(I:I))))
It looks like Google Apps Script now supports ranges as function parameters. This solution accepts a range:
// Returns row number with the last non-blank value in a column, or the first row
// number if all are blank.
// Example: =rowWithLastValue(a2:a, 2)
// Arguments
// range: Spreadsheet range.
// firstRow: Row number of first row. It would be nice to pull this out of
// the range parameter, but the information is not available.
function rowWithLastValue(range, firstRow) {
// range is passed as an array of values from the indicated spreadsheet cells.
for (var i = range.length - 1; i >= 0; -- i) {
if (range[i] != "") return i + firstRow;
}
return firstRow;
}
Also see discussion in Google Apps Script help forum: How do I force formulas to recalculate?
I looked at the previous answers and they seem like they're working too hard. Maybe scripting support has simply improved. I think the function is expressed like this:
function lastValue(myRange) {
lastRow = myRange.length;
for (; myRange[lastRow - 1] == "" && lastRow > 0; lastRow--)
{ /*nothing to do*/ }
return myRange[lastRow - 1];
}
In my spreadsheet I then use:
= lastValue(E17:E999)
In the function, I get an array of values with one per referenced cell and this just iterates from the end of the array backwards until it finds a non-empty value or runs out of elements. Sheet references should be interpreted before the data is passed to the function. Not fancy enough to handle multi-dimensions, either. The question did ask for the last cell in a single column, so it seems to fit. It will probably die on if you run out of data, too.
Your mileage may vary, but this works for me.
function lastRow(column){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var lastRow = sheet.getLastRow();
var lastRowRange=sheet.getRange(column+startRow);
return lastRowRange.getValue();
}
no hard coding.
In a column with blanks, you can get the last value with
=+sort(G:G,row(G:G)*(G:G<>""),)
This gets the last value and handles empty values:
=INDEX( FILTER( H:H ; NOT(ISBLANK(H:H))) ; ROWS( FILTER( H:H ; NOT(ISBLANK(H:H)) ) ) )
The answer
$ =INDEX(G2:G; COUNT(G2:G))
doesn't work correctly in LibreOffice. However, with a small change, it works perfectly.
$ =INDEX(G2:G100000; COUNT(G2:G100000))
It always works only if the true range is smaller than (G2:G10000)
Is it acceptable to answer the original question with a strictly off topic answer:)
You can write a formula in the spreadsheet to do this. Ugly perhaps? but effective in the normal operating of a spreadsheet.
=indirect("R"&ArrayFormula(max((G:G<>"")*row(G:G)))&"C"&7)
(G:G<>"") gives an array of true false values representing non-empty/empty cells
(G:G<>"")*row(G:G) gives an array of row numbers with zeros where cell is empty
max((G:G<>"")*row(G:G)) is the last non-empty cell in G
This is offered as a thought for a range of questions in the script area that could be delivered reliably with array formulas which have the advantage of often working in similar fashion in excel and openoffice.
function getDashboardSheet(spreadsheet) {
var sheetName = 'Name';
return spreadsheet.getSheetByName(sheetName);
}
var spreadsheet = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
var dashboardSheet = getDashboardSheet(spreadsheet);
Logger.log('see:'+dashboardSheet.getLastRow());
I was playing with the code given by #tinfini, and thought people might benefit from what I think is a slightly more elegant solution (note I don't think scripts worked quite the same way when he created the original answer)...
//Note that this function assumes a single column of values, it will
//not function properly if given a multi-dimensional array (if the
//cells that are captured are not in a single row).
function LastInRange(values)
{
for (index = values.length - 1; values[index] == "" && index > 0; index--) {}
return String(values[index]);
}
In usage it would look like this:
=LastInRange(D2:D)
Regarding #Jon_Schneider's comment, if the column has blank cells just use COUNTA()
=INDEX(G2:G; COUNT**A**(G2:G))
I found another way may be it will help you
=INDEX( SORT( A5:D ; 1 ; FALSE) ; 1 ) -will return last row
More info from anab here:
https://groups.google.com/forum/?fromgroups=#!topic/How-to-Documents/if0_fGVINmI
Found a slight variation that worked to eliminate blanks from the bottom of the table.
=index(G2:G,COUNTIF(G2:G,"<>"))
I'm surprised no one had ever given this answer before. But this should be the shortest and it even works in excel :
=ARRAYFORMULA(LOOKUP(2,1/(G2:G<>""),G2:G))
G2:G<>"" creates a array of 1/true(1) and 1/false(0). Since LOOKUP does a top down approach to find 2 and Since it'll never find 2,it comes up to the last non blank row and gives the position of that.
The other way to do this, as others might've mentioned, is:
=INDEX(G2:G,MAX((ISBLANK(G2:G)-1)*-ROW(G2:G))-1)
Finding the MAXimum ROW of the non blank row and feeding it to INDEX
In a zero blank interruption array, Using INDIRECT RC notation with COUNTBLANK is another option. If V4:V6 is occupied with entries, then,
V18:
=INDIRECT("R[-"&COUNTBLANK(V4:V17)+1&"]C",0)
will give the position of V6.
to get the last value from a column you can also use MAX function with IF function
=ARRAYFORMULA(INDIRECT("G"&MAX(IF(G:G<>"", ROW(G:G), )), 4)))
I have gone through way too many of these implementations of last-row for a specific column. Many solutions work but are slow for large or multiple datasets. One of my use cases requires me to check the last row in specific columns across multiple spreadsheets. What I have found is that taking the whole column as a range and then iterating through it is too slow, and adding a few of these together makes the script sluggish.
My "hack" has been this formula:
=ROW(index(sheet!A2:A,max(row(sheet!A2:A)*(sheet!A2:A<>""))))-1
Example: Add this to Cell A1, to find the last row in column A. Can be added anywhere, just make sure to manage the "-1" at the end depending on which row the formula is placed. You can also place this is another col, rather than the one you're trying to count, and you don't need to manage the -1. You could also count FROM a starting Row, like "C16:C" - will count values C16 onwards
This formula is reliably giving me the last row, including blanks in the middle of the dataset
To use this value in my GS code, I am simply reading the cell value from A1. I understand that Google is clear that spreadsheet functions like read/write are heavy (time-consuming), but this is much faster than column count last-row methods in my experience (for large datasets)
To make this efficient, I am getting the last row in a col once, then saving it as a global variable and incrementing in my code to track which rows I should be updating. Reading the cell every-time your loop needs to make an update will be too inefficient. Read once, iterate the value, and the A1 cell formula (above) is "storing" the updated value for the next time your function runs
Please let me know if this was helpful to you! If I encounter any issues I will comment on this answer.
=QUERY({G2:G9999,ARRAYFORMULA(ROW(G2:G9999))},"Select Col1 where Col1 is not null Order By Col2 desc limit 1",0)
In the query, Col1 refers to column G, and Col2 refers to a virtual column, populated with the row numbers returned by ARRAYFORMULA(ROW(G2:G9999)).
I haven't evaluated the other answers, so I can't say if this is the best way, but it worked for me.
Bonus: to return the first non-empty cell:
QUERY({G2:G9999},"Select Col1 where Col1 is not null limit 1",0)
Refs: QUERY, ARRAYFORMULA, ROW.