Add a column with a specific value when making google sheet "=QUERY" - google-sheets

I am sorting an array made up of 2 queries.
I want to add an additional row per query with a prefilled value.
Full query:
=SORT({
QUERY(Materials!A4:K,"SELECT A,D,K,J where B='"&Home!C9&"'") ;
QUERY(Labour!A4:K,"SELECT A,D,H,G where B='"&Home!C9&"'")
}, 1, 1)
Example of currently returned columns/values:
QUERY(Materials!A4:K,"SELECT A,D,K,J where B='"&Home!C9&"'")
date1, supplier1, notes1, amount1
date2, supplier1, notes2, amount2
date3, supplier2, notes3, amount4
QUERY(Labour!A4:K,"SELECT A,D,H,G where B='"&Home!C9&"'")
date1, joblocation1, notes1, amount1
date2, joblocation2, notes2, amount2
What I would like the final output to be:
Name1, Materials, supplier1, notes1, amount1
Name2, Materials, supplier1, notes2, amount2
Name3, Materials, supplier2, notes3, amount4
date1, Labour, notes1, amount1
date2, Labour, notes2, amount2
.. thus as per the title, "adding a column with a specific value when making a google sheet query"

To Add an additional untitled column, here is one possible solution:
QUERY(Materials!A4:K,"SELECT A,D,K,J where B='"&Home!C9&"'")
To
QUERY(Materials!A4:K,"SELECT A,'NewColValue',D,K,J where B='"&Home!C9&"' label 'NewColValue' ''")

Related

get data by duration (daily, weekly, monthly) in neo4j CQL

New to neo4j.
My neo4j relationships look something like....
(p:Person{
name:"XYZ",
joinDate:'date_ in_datetime_format'
})
-[:PART_OF]->
(c:Club {name:"ABC"})
I want to produce a list of members for durations like daily, weekly, monthly, quarterly, yearly. So if duration is Daily, I want to get 'no. of people added' for all days along with a index (list of {ratio, index}). Same goes for weekly, monthly and so on...
I want to write different queries for different duration cases.
I know how to count all schemes and members and hot get the cases, the thing I am getting stuck at counting members added in a duration like daily, weekly, and so on.
Cypher has an automatic groupBy where the key on the left is the aggregation key and the rest is automatically grouped by that key.
https://neo4j.com/docs/cypher-manual/current/functions/aggregating/
So if you return the day of the Person joinDate property and a count(*) it will do what you're looking for.
For months you return the month, for quarters you return the quarters. You can check here about instant values possible https://neo4j.com/docs/cypher-manual/current/syntax/temporal/#cypher-temporal-accessing-components-temporal-instants
For daily :
(p:Person{
name:"XYZ",
joinDate:'date_ in_datetime_format'
})
-[:PART_OF]->
(c:Club {name:"ABC"})
RETURN p.joinDate.year + '-' + p.joinDate.month + '-' p.joinDate.day AS window, count(*) AS count
For monthly :
(p:Person{
name:"XYZ",
joinDate:'date_ in_datetime_format'
})
-[:PART_OF]->
(c:Club {name:"ABC"})
RETURN p.joinDate.year + '-' + p.joinDate.month AS window, count(*) AS count
For quarterly :
(p:Person{
name:"XYZ",
joinDate:'date_ in_datetime_format'
})
-[:PART_OF]->
(c:Club {name:"ABC"})
RETURN p.joinDate.year + '-' p.joinDate.quarter AS window, count(*) AS count
For yearly :
(p:Person{
name:"XYZ",
joinDate:'date_ in_datetime_format'
})
-[:PART_OF]->
(c:Club {name:"ABC"})
RETURN p.joinDate.year AS window, count(*) AS count

How to use dynamic array formula to filter and format data

I am facing a problem related to the dynamic array.
I have data in the below format.
And I want to convert to this format.
Here is the sheet link.
I am using this formula to filter Fruits category.
={FILTER(A5:D11,B5:B11="Fruits");SUM( FILTER(D5:D11,B5:B11="Fruits"))}
But it gives this error
In ARRAY_LITERAL, an Array Literal was missing values for one or more rows
NOTE: Data should be pulled dynamically from the formula, as the data may change.
To build the result table without hard coding category names in the formula, use the recently introduced lambda functions, like this:
={
lambda(
data, categories, headers, totalsHeader, blankRow, selectPrice,
reduce(
headers, query(unique(categories), "where Col1 is not null", 0),
lambda(
resultTable, filterKey,
{
resultTable;
lambda(
filterData,
{
filterData;
{ totalsHeader, query(filterData, selectPrice, 0) };
blankRow
}
)(filter(data, categories = filterKey))
}
)
)
)(
B5:D,
B5:B,
B4:D4,
{ "", "Total:" },
{ "", "", "" },
"select sum(Col3) label sum(Col3) '' "
);
{ "", "Grand Total:", sum(D5:D) }
}
See { array expressions }, filter(), query(), reduce() and lambda().
The formula will repeat each category name on several rows. If they get in the way, you can hide them from view by using a conditional formatting custom formula rule.
I did some tests to add all the information in just one formula. It will change the format you want, but it will still divide all the information.
Here is the formula:
={"Fruits:","";QUERY(B5:D,"select C, D where B ='Fruits'");
{"Total:",SUMIF(B5:D,"Fruits",D5:D)};"","";
"Vegetables:","";QUERY(B5:D,"select C, D where B ='Vegetables'");
{"Total:",SUMIF(B5:D,"Vegetables",D5:D);"","";
"condiments:","";QUERY(B5:D,"select C, D where B ='condiments'");
{"Total:",SUMIF(B5:D,"condiments",D5:D)};"","";
"Grand Total:",SUM(D5:D)}}
Note:
I added : and the end of each category in the formula so they will look like Fruits: and the table will look like this:
The formula opens with { to open an array in Google Sheets, and you use , to separate columns to write a row of data, and ; to separate the rows to help you write a column of data. After that, you use } to close the array. For example:
{"1","2";"3","4"}
It will print:
So basically, I organize the data with arrays of the same amounts of columns. The first one with part
= { => To open the array.
"Fruits:",""; => This create a cell with "Fruits:" + an empty cell.
QUERY(B5:D,"select C, D where B ='Fruits'"); => which is
already on an array of 2 columns.
{"Total:",SUMIF(B5:D,"Fruits",D5:D)}; => Creates the "Total" cell + the sum
of values that has Fruits in column B.
"",""; => Which will create an empty row to separate the information
for the next set of arrays.
You do the same pattern for the other categories.
} => to end the initial array.
You can add a "Conditional formatting" that will change the text with : to bold automatically.
Reference:
QUERY function
SUMIF
ARRAYFORMULA
I suggest you read on: https://stackoverflow.com/a/58042211/5632629
the first part of your formula outputs a grid of 4×3 cells
the second part of your formula outputs a single cell
if you want to combine it properly use:
={FILTER(A5:D11, B5:B11="Fruits");
{"","","Totals",SUM(FILTER(D5:D11, B5:B11="Fruits"))}}
or:
={FILTER(B5:D11, B5:B11="Fruits");
{"","Totals",SUM(FILTER(D5:D11, B5:B11="Fruits"))}}

Select 'x' returns "x"()

I want to return 3 columns, A(description), 'D'(hard coded value of D), Q(date)
=query('Detailed Plan'!$A$2:$Q, "select A,'D',Q where D = date)
It returns the following results. Rows 2 and greater are exactly what I want and would be perfect if I didn't get the first row. How do I get a hard coded value into a column without "D"() showing up in the first row?
blank, "D"(), blank
Description, D, date
Description, D, date
Description, D, date
Thanks so much for any help that is provided.
You can use 'label' in the query string.
=query('Detailed Plan'!$A$2:$Q, "select A, D, Q where D = date label A 'Description', D 'Some value', Q 'Date' ", 0)
EDIT: if you don't need headers at all, try
=query('Detailed Plan'!$A$2:$Q, "select A, D, Q where D = date ", 0)

Generate string like Q,R,S...AB where AB is last column in Google Sheet

I have a complex Google Sheet query that works great except when a Google Sheet doesn't have as many columns as I use in my formula.
Here's what the formula looks like now:
=sum(filter(query(INDIRECT("'" & A2 & "'!$A$7:$23"),"select Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH where B='"&C2&"'",0),query(INDIRECT("'" & A2 & "'!$A$7:$23"),"select Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH where B='PROJECT'",0) >=date(2017,1,1),query(INDIRECT("'" & A2 & "'!$A$7:$23"),"select Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH where B='PROJECT'",0) <=date(2017,12,31)))
It works great. But the problem is I run it against many worksheets and some don't have e.g. column AG,AH and end at AF at which point I get an error.
So what I need is a way to generate the string Q,R,S....[Name of Last Column in Sheet] and then I can use that instead of my hard-coded Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH but I cannot figure out how to do that.
Any help is greatly appreciated. Thanks!
Per comments above, final formula was:
LEFT("Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,A‌​L,AM,AN,AO,AP,AQ,AR,‌​AS,AT,AU,AV,AW,AX,AY‌​,AZ,BA,BB,BC ",2*Columns(INDIRECT(A2&"!1:1"))-33+IF(Columns(INDIRECT(A2&"‌​!1:1"))>26,Columns(I‌​NDIRECT(A2&"!1:1"))-‌​26,0))
where column A contains the list of worksheets (tabs) in the Google Sheet. Put this in B2, and then copied it down. I am not marking this as the correct answer since others gave a correct formula-based answer but this did the trick for me.
This can be done with built-in functions:
On a helper sheet, let say you name it, helper, fill up range with letters A to Z, let say A1:A26
Let say that on B1 you write the following formula:
=ArrayFormula({A1:A26;TRANSPOSE(SPLIT(JOIN(",",SUBSTITUTE(QUERY(TRANSPOSE(A1:A26)&A1:A26,,27)," ",",")),","))}) . This will create a list of column letter headers.
On each new worksheet use columns(1:1) to get the total number of columns.
To get your string of column headers, then you could use something like :
JOIN(",",OFFSET(helper!B1,16,0,columns(1:1)-16))
QUERY(helper!B:B,"select B limit "&columns(1:1)-7&" offset 7")
NOTE:
If you decide to have only one helper sheet and use it on several spreadsheets, then use
QUERY(IMPORTRANGE(your_url,"helper!B:B"),"select Col1 limit "&columns(1:1)-7&" offset 7")
This can be done with script. Without seeing you spreadsheet, it is hard to know exactly what you need, but this should be close. I get the variables from Sheet1 and return the formula to Sheet1. Adjust the sheet name to fit your needs. This will look at your data sheets based on the variable sheet name determine the last column. Determine the column letters and build the string the query needs. It then sets the new query formula. I added a menu to run it from.
function onOpen() {
SpreadsheetApp.getActiveSpreadsheet().addMenu(
'Create Data', [
{ name: 'Run', functionName: 'formula' },
]);
}
function formula(){
var ss= SpreadsheetApp.getActiveSpreadsheet()
var s=ss.getSheetByName("Sheet1") //sheet where variables are
var sheet=s.getRange("A2").getValue()//variable sheet name
var sel=makeString(sheet) //get the select string of column letters
//Create formula and return to Sheet1 A3
var f= s.getRange("A3").setFormula('=sum(filter(query(INDIRECT("\'" & A2 & "\'!$A$7:$23"),"select '+sel+' where B=\'"&C2&"\'",0),query(INDIRECT("\'" & A2 & "\'!$A$7:$23"),"select '+sel+' where B=\'PROJECT\'",0) >=date(2017,1,1),query(INDIRECT("\'" & A2 & "\'!$A$7:$23"),"select '+sel+' where B=\'PROJECT\'",0) <=date(2017,12,31)))')
}
function makeString(sht){
var ss= SpreadsheetApp.getActiveSpreadsheet()
var s=ss.getSheetByName(sht)
var lc=s.getLastColumn()
var rng=s.getRange(1, 17, 1, lc).getValues()
var str=''
var ltr=[]
for(var i=17;i<rng[0].length+1;i++){
ltr[i]= columnToLetter(i)
str=ltr.join(',')
}
var str1=str.substr(17)
return str1
}
function columnToLetter(column)
{
var temp, letter = '';
while (column > 0)
{
temp = (column - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column = (column - temp - 1) / 26;
}
return letter;
}
Let me know if you have any questions.

Neo4j Aggregate Multiple Lines into a Map

I have the following Cypher script:
MATCH (sy:SchoolYear)<-[:TERM_OF*]-()<-[:DAY_OF]-(d:Day)
WHERE sy.year = 2015
OPTIONAL MATCH (d)<-[:START]-(e:Enrollment)-[:AT]->(s:School)
RETURN d.date, s.abbreviation, count(e)
ORDER BY d.date
This gives me all of the dates in the range that I want and returns number of students that have enrolled for each school for that date, or null. The only issue I have is that different schools are on different lines, causing a single date to have multiple lines. I would like to aggregate those into a single line per date.
I'm given:
1/1/2000, School 1, 5
1/1/2000, School 2, 10
1/2/2000, null, null
1/3/2000, School 1, 6
What I would like:
1/1/2000, {School 1 : 5, School 2: 10}
1/2/2000, null
1/3/2000, {School 1: 6}
I've tried:
MATCH (sy:SchoolYear)<-[TERM_OF*]-()<-[:DAY_OF]-(d:Day)
WHERE sy.year = 2015
OPTIONAL MATCH (d)<-[:START]-(e:Enrollment)-[:AT]->(s:School)
WITH d, s.abbreviation as abb, count(e) as enr
RETURN d.date, {abb:enr}
ORDER BY d.date
How should I go about this?
Here is how I would go with this aggregate each school into a map and the maps into a collection
MATCH (sy:SchoolYear)<-[TERM_OF*]-()<-[:DAY_OF]-(d:Day)
WHERE sy.year = 2015
OPTIONAL MATCH (d)<-[:START]-(e:Enrollment)-[:AT]->(s:School)
WITH d, s, count(e) as students
RETURN d.date, collect({name:s.abbreviation, students:students})
ORDER BY d.date
This is a bit ugly, but I think it returns what you are after. I tried using the school name as a key just like you did in your example and I could not get that to work either. In the end I resorted to this.
MATCH (sy:SchoolYear)<-[TERM_OF*]-()<-[:DAY_OF]-(d:Day)
WHERE sy.year = 2015
OPTIONAL MATCH (d)<-[:START]-(e:Enrolment)-[:AT]->(s:School)
// collect the schools and their counts together
with d, [s.abbreviation, count(e)] as school_count
// collect all of the school counts together by date
with d.date as date, collect(school_count) as school_counts
// format the school counts as a string with the schools
// as keys and the counts as values
with date, reduce( out = "", s in school_counts | out + s[0] + " : " + s[1] + ", " ) as school_count_str
return date, '{ ' + left(school_count_str, length(school_count_str)-2) + ' }' as school_counts
order by date

Resources