I've been asked to create a summary for some google form responses, and though I have a working solution, I can't help but feel there must be a more elegant one.
The form collects data related to case checking - every month each team (there's 100+ teams) has to check a certain number of cases based on how many staff are in their team, and enter the results for each case they've checked in the google form. The team that have set this up want me to summarise the data by team, month, and section of the form (preliminary questions, case recording, outcomes, etc). There are 8 sections on the live form, ranging from 1-13 questions, all with Yes/No/NA/blank answers.
(honestly, it's not how I'd have approached setting all this up, but that is out of my hands!)
So they're essentially looking for a live monthly summary with team names down the side, section names along the top, and a %age completed that will keep up with entries as they come in (where we can also use importrange and query to pull the relevant bits into other google sheet summaries, as and when needed).
What I've currently got is this:
=iferror(sum(countifs('Form Responses'!$B:$B,$A3,'Form
Responses'!$F:$F,"Yes",'Form Responses'!$E:$E,">="&$B$1,'Form
Responses'!$E:$E,"<"&edate($B$1,1)),countifs('Form
Responses'!$B:$B,$A3,'Form Responses'!$G:$G,"Yes",'Form
Responses'!$E:$E,">="&$B$1,'Form
Responses'!$E:$E,"<"&edate($B$1,1)),countifs('Form
Responses'!$B:$B,$A3,'Form Responses'!$H:$H,"Yes",'Form
Responses'!$E:$E,">="&$B$1,'Form
Responses'!$E:$E,"<"&edate($B$1,1)),countifs('Form
Responses'!$B:$B,$A3,'Form Responses'!$I:$I,"Yes",'Form
Responses'!$E:$E,">="&$B$1,'Form
Responses'!$E:$E,"<"&edate($B$1,1)),countifs('Form
Responses'!$B:$B,$A3,'Form Responses'!$J:$J,"Yes",'Form
Responses'!$E:$E,">="&$B$1,'Form
Responses'!$E:$E,"<"&edate($B$1,1)),countifs('Form
Responses'!$B:$B,$A3,'Form Responses'!$K:$K,"Yes",'Form
Responses'!$E:$E,">="&$B$1,'Form
Responses'!$E:$E,"<"&edate($B$1,1)))/(countifs('Form
Responses'!$B:$B,$A3,'Form Responses'!$E:$E,">="&$B$1,'Form
Responses'!$E:$E,"<"&edate($B$1,1))*6),0)
It works, but it feels like a bit of a brute-force-and-ignorance solution. I've tried countifs & array, I've looked a pivot but I can't get the section groups, I've had a play with query but I can't figure out how to ask it to count all Yeses in multiple columns at once.
Is there a more elegant solution, or do I have to resign myself to setting up the next financial year's summaries like this?
Edit:
You can use plain array boolean multiplication to achieve the count, as trues are converted to 1s and false are converted to 0s:
=TO_PERCENT(ARRAYFORMULA(
SUM((f!F1:K="Yes")*(f!E1:E>=B1)*(f!E1:E<EDATE(B1,1))*(f!B:B=A3))/
SUM(6*(f!E1:E>=B1)*(f!E1:E<EDATE(B1,1))*(f!B:B=A3))
)
)
Renamed Form Responses to f
Numerator: SUM of
Question filter (f!F:K =Yes) and
Month filter (f!E:E is within month of B1) and
Team filter(B:B = A3)
Denominator: 6 times the SUM of
Month filter (f!E:E is within month of B1) and
Team filter(B:B = A3)
On this sample sheet that you provided you'll notice two new tabs. MK.Retab and MK.Summary.
On MK.Retab is a single formula in A2 that "re-tabulates" all of your survey data into a format that is much easier to analyze going forward. That tab can be "hidden" on your real project. It will continue to build the 6 column dataset forever. It would be a sort of "back end" sheet, only used to supply data to any further downstream analysis.
On MK.Summary is a single formula in cell A1 that Query's that dataset from MK.Retab and shows the percentage of Yes's by month by section by team in a format similar to what you proposed. I coded it to display the most recent month at the left, immediately to the right of the team names, and to push historical data off to the right. Even though people are often used to seeing time go from left to right, I find that the opposite method nice because it keeps you from having to scroll sideways to see the most recent data. It is very simple to change should you want to by getting rid of the "desc" that you find in the "order by" clause of the query string.
I find this kind of two step solution to problems like your useful, because while the summary migth not be exactly what you want, it's always easier to build formulas and analyses off of the data as laid out in the MK.Retab sheet.
As for the formula in MK.Retab, it is based on a method that I came up with a while back that constructs a large vlookup where the [search key] is actually a sequence of decimal numbers that is built by counting the number of rows in your real data set and multiplying by the number of columns of data that need to be repeated for each row. I built a demo some time ago that I'm happy to share with folks if you want to understand better how it works.
You said that your goal was to understand the formulas so that you could modify them going forward as needed. I'm not sure how easy that will be to do, but I can try my best to answer any questions you might have about the method or the solution generally.
What I can tell you is that some of the formulas are more complicated than they need to be because you just used Q1 Q2 Q3 etc instead of the actual questions. if you had a list of the questions asked somewhere (on some other tab, say), and what you wanted to call/name their corresponding "sections", it would make the formula significantly less complicated. As it stands, I had to use the appearance of the word "Comments", in row 1 to distinguish between where one section ended and another section began. The upside to that decision though, is that the formula I wrote is infinitely expandable to the right. That is, if you were to add another 100 columns worth of questions and answers to the sample set here, the formula would be able to handle that and break it out, so long as there was the word "Comments" between each section.
Hope all this helps.
I'm trying to get the rank of a spell, but GetSpellInfo does not return the second parameter (rank). If I run:
/dump GetSpellInfo( 5782 )
I get
[1]="Fear"
[3]="136813"
[4]="1500"
[5]="0"
[6]="20"
[7]="5782"
Each combination of spell and rank seem to have a unique ID:
5185 = Healing Touch (rank1)
5186 = Healing Touch (rank2)
5187 = Healing Touch (rank3)
5188 = Healing Touch (rank4)
5189 = Healing Touch (rank5)
6778 = Healing Touch (rank6)
8903 = Healing Touch (rank7)
9758 = Healing Touch (rank8)
How do I get the spell rank given an ID?
The mod I'm working on (LunarSphere) gets a drag from the spellbook.
I'm using that with a button SetAttribute:
self:SetAttribute("*spell-S01", "Healing Touch")
For the highest rank or
self:SetAttribute("*spell-S01", "Healing Touch(rank 3)")
For a specific rank
Thanks!
They are just different spells. It makes it awkward for certain things where we tend to see them as different ranks of the same spell.
You will likely have to make a DB of the ranked spells and do a lookup in your own tables as part of the overall service provided by your addon.
https://wowwiki.fandom.com/wiki/API_GetSpellInfo
rank (string) - The rank line from the tooltip of the spell, e.g. "Rank 2". Returns some other classification (like "Summon" for a summoning
spell) or an empty string if there is no rank.
So that "rank" is for just displaying the extra line in the UI, if they wanted to add one for that spell.
Like many things in the UI API, they are just there to support the UI and mostly pragmatic and just what's necessary to display or do WoW UI functionality.
local subTextOrRank = GetSpellSubtext(spellId)
This gets the display line for rank which newer engines may not return with spell info. 'GetSpellSubtext' may or may not return the rank text if the spell is cached on the client or not, or maybe you end up seeing it works every time.
I have used this spell list for quick reference in the past:
http://kyle.13th-floor.org/wow/spells/spells_2_4_0.txt
For answering many questions about the data the client has available statically:
https://wow.tools/dbc/
Here is an example of the client SpellName table from a current version of WoW Classic:
https://wow.tools/dbc/?dbc=spellname&build=1.13.3.32836#search=&page=1
Here is the Spell table from the same WoW Classic version:
https://wow.tools/dbc/?dbc=spell&build=1.13.3.32836#search=&page=1
ID, NameSubtext_lang, Description_lang, AuraDescription_lang
1
3
4
5, , Instantly Kills the target. I hope you feel good about yourself now.....
7
10, Rank 1, Ice shards pelt the target area doing $o1 Frost damage over $d.
11
Here you can see that they literally made a table of what the UI needed for display and its no more complicated or deep than that.
And if you read down the list can see or imagine it's basically done by hand, and thus can have mistakes or may have text that helps the rank description field but breaks the consistency. This is important to note that if you are going to rely on table string fields for programmatic purposes where you will need to be aware of and add exceptions to your test for rank.
You could attempt to roll through the spell list on load and build a rank list on the fly, but be aware that there are 21,000 spells in that table. If you are only worried about player spells you could make a mini pre-built list stored as a table for your own addon, and it would be a table only in the hundreds. You could have the base English name and a min and max field for rank.
I think 'GetSpellSubtext' in a loop to spit out a Lua table on your local client, in combination with the tables and rolling a small DB may break the log jam for you.
So, it might be a silly question, but I find it really difficult to search for an answer with a simple query and felt like I needed to post a more complex question to get my point across and get an answer. Really sorry if this has been asked before, but I'm not a native Eng speaker and I don't know which phrases to sue when looking for this.
What I want to do is create a Google Spreadsheet to ease character creation for an RPG game for my friends.
There are lots of choices during creation, of course, and I need to be able to get one result from multiple variables. To make it clear, I'll use an example from creation:
It's based on priority system A-E. If the player chooses priority A for race and chooses human as race, they get 9 points to spend on attributes.
I need a function that would check one cell for priority letter, the other for race name and give me a result based on those two, so in the given example, it'd be something like:
'if A2 = "A" and B2 = "Human" then C2 = 9.
I know it's entirely not how functions are written, but I'm trying to describe the calculation I'm trying to run.
I'd be grateful for any and all the help!
try something like:
=IFERROR(VLOOKUP(A10; A1:F8; MATCH(B10; A1:F1; 0); 0))
My scripting skills are not the greatest but I can not figure out how to accomplish what I need to with just functions inside of Google Sheets.
My sheet looks something like this: https://docs.google.com/spreadsheets/d/1R6YJIR37wtOt8ZknSdMQPFFp0Llf_LHpmGCV32iQY00/edit#gid=1213399830
I have form responses being brought into the second tab via the Indirect function and are then modified with a ArrayFormula function to convert everything to the correct unit of measure and the summed to keep everything on the same row. All of this could be altered if needed.
I then have a column that is totaling inputs in other columns to give me my on hand inventory. We'll call this TotalsColumn.
What I am attempting to achieve is to make a script that checks the form responses, then either with:
OnEdit (which if I understand correctly does not work for information being ported in) and then alter the corresponding cell in the TotalsColumn.
or if not possible, then
With a time based trigger checking the ported information to see if there is a new entry if I don't sum it with a last function or something, or if the information remains summed (which seems easier to me) then to check if the sum is greater than it was last time it was checked and alter TotalsColumn.
The alter to the TotalsColumn, regardless of which method used, will always be a static number and I am pretty sure I'll need to make a script for each of my different inventory items but that's fine if I can just figure out a way of making this happen.
Thank for your time and any information you can provide.
Please feel free to point me to another thread where I can start to piece together a solution, I just could not find anything that related closely enough to my question or find a good jumping off point.
What happens in this situation?
I'm looking into using Ice Cube https://github.com/seejohnrun/ice_cube for recurring events.
My question is, if I then need to get any events that fall within a given time period (say, on a day or within a week), is there any better way than to loop through them all like this:
items = Records.find(:all)
items.each do |item|
schedule = item.schedule
if schedule.occurs_on?(Date.new)
#if today is a recurrence, add to array
end
end
This seems horribly inefficient but I'm not sure how else to go about it.
That's one approach - but what people do more often is end up denormalizing their schedules into a format that is conveniently queryable.
You may have a collection called something like ScheduleOccurrences - that you build each week / and then query that instead.
Its unfortunate it has to work this way, but sticking to the iCal way of managing schedules has led IceCube to need to format its data in certain ways (specifically ways that can line up with the requirements of the iCal RFC).
I've been doing some thinking recently about what a library would look like that shook away some of those restrictions, for greater flexibility like this - but its definitely still a bit off.
Hope this helps
I faced a similar problem and here was my approach:
Create a column on Event table to store the next occurrence date, and write a method which stores that value after_save. (method available through ice_cube. Perhaps index column too for faster querying.)
Then you can query the database for occurrences happening in the timeframe you need. See below:
Event.where(next_occurrence: Date.today.all_day)
Store EventOccurrences on a separate table.
Update the next_occurrence column for the rows returned to you by your query. Or something similar. This works for me because I'm running a daily job, so that update next_occurrence will run regularly. But you may need to tweak a bit.