I have the following table on one sheet, top table of the picture, and I need to transform it to the to the different format on the second sheet (bottom table of the picture). I need to use VBA in Excel to do this manipulations. I pulled the main table (top) from SQL query on the separate sheet and need to rearrange it to fit my needs. I have a lot more data than that but it follows the same format. Just imagine that there are just more Shelves, Items, Amounts and Stores.
I searched everywhere but can't seem to find direct answer.
I am relatively new to VBA. Can someone give me a some directions? Is there a website with some tutorials about table manipulations in Excel VBA?
Beyond an intellectual pursuit, there is absolutely no need for VBA. From your example, put this array formula in C24.
=IFERROR(INDEX($B$2:$B$23, MATCH(0, IF(LEN($B$2:$B$23), COUNTIF($B24:B24, $B$2:$B$23), 1), 0)), "")
Finalize with Ctrl+Shift+Enter↵. Once entered correctly, fill right until you run out of values to retrieve.
In A25 use this standard formula.
=IF(COUNTIF(A$24:A24, MOD(ROW(1:1)-1, MAX(A$2:A$23))+1)<SUMPRODUCT((D$2:D$23<>"")/COUNTIF(D$2:D$23, D$2:D$23&"")), MOD(ROW(1:1)-1, MAX(A$2:A$23))+1, "")
Fill down to get all of the shelves you will need.
In B25 use this array formula,
=IF(AND(ROW(1:1)>1,COUNTIF(A$24:A25, A25)=COUNTIF(A$24:A24, A24)), B24, IFERROR(INDEX($D$2:$D$23, MATCH(0, IF(LEN($D$2:$D$23), COUNTIF(B$24:B24, $D$2:$D$23), 1), 0)), ""))
Finalize with Ctrl+Shift+Enter↵. Fill down to catch all of the stores.
Finally, put this in C25.
=SUMIFS($C$2:$C$23, $A$2:$A$23, $A25, $B$2:$B$23, C$24, $D$2:$D$23, $B25)
Fill right to D25 then fill C25:D25 down to the length of the table.
The only difference in my second table is that Water comes before Gartorade and that is a result of it appearing the first table's Item list first.
Related
I am combining several spreadsheets with identical layouts into one master, and want to create a way to have my query({importrange}) be dynamic, as I will be adding / removing some sheets as time goes on. I have all of my sheet addresses in column C, so my formula right now looks like:
=QUERY({Importrange(C4,Sheet1!C5:F);Importrange(C5,Sheet1!C5:F);...}
This works fine, but any time I add/remove a sheet I would have to edit a very long string.
Is there a way for QUERY or IMPORTRANGE to reference another cell that combines my various spreadsheets listed in column C?
I've tried variations of CONCATENATE, JOIN, etc to combine C into one cell that is referenced in the QUERY OR IMPORTRANGE, but no luck so far.
Trying to future-proof a little...
no, but you can do this:
={""; ARRAYFORMULA("=QUERY({"&TEXTJOIN("; ", 1,
IF(C4:C="",,"IMPORTRANGE("""&C4:C&""", ""Sheet1!C5:F"")"))&
"}, ""where Col1 is not null"", )")}
so it will automatically create a formula for you and then you just copy-paste it where you need it
Link to example file:
https://docs.google.com/spreadsheets/d/1dCQSHWjndejkyyw-chJkBjfHgzEGYoRdXmPTNKu7ykg/edit?usp=sharing
The tab "Source data" contains the data to be used in the query on the tab "Query output". The tab "Desired result" shows what I would like the end result to look like.
The goal I'm trying to achieve is to have the formula in cell A2 on the tab "Query output" to populate the data in all four of the columns, so that it looks exactly like the "Desired result" tab. I know I can get the same result simply by entering additional formulas in C2 and D2, but this is not the objective, I need the results to come specifically from the single formula in A2.
The information in the "Additional data 1" column should simply repeat the word "Test" for every row that contains data in the first two columns. The information in the "Additional data 2" column should simply repeat the data from cell 'Source data'!A1 for every row that contains data in the first two columns.
Please feel free to edit the example file as it only contains dummy data. If you like, you can copy the tab "Query output" to create your own working formula for illustrative purposes.
EDIT:
I'm thinking along the lines of creating an array that consists of the required data for the columns "Additional data 1" and "Additional data 2" and then combining that array with the array of the query result which provides the first two columns. I've been experimenting with this in various ways, but so far the only result I have achieved is an error on the first cell of the query results. I also have no idea yet how I could make sure that the second array contains an equal amount of rows to the query result.
You can add static data into query:
=QUERY('Source data'!A3:B,"SELECT A,B, 'Test', '" & 'Source data'!A1 &"' WHERE A IS NOT NULL LABEL A '', B '', 'Test' '', '" & 'Source data'!A1 &"' ''")
Many thanks to #basic for the provided assistance! The insights were a great help to solving my issue. That said, I have muddled along a bit, and I've come up with a slightly different solution which I find better suited as it gives true blank values instead of a column filled with spaces.
First of all, instead of querying directly on the source data, I built an array and queried on that. I used the two existing columns (A and B) from the source data and added a third column to the array which does not exist in the source data. In order to make sure that the third column would consist of blank values, I used the IFERROR formula.
=IFERROR(0/0)
The formula above returns a blank because dividing by zero forces an error and the IFERROR method returns a blank unless an alternative return value is specified.
In order to be able to use this formula in an array however, it had to be tweaked slightly, because as it is it would only return a single blank cell value instead of a column of blank values. To do this, I used an already existing column from the source data, and then encapsulated it in an ARRAYFORMULA.
=ARRAYFORMULA(IFERROR('Source data'!A3:A/0))
Using this, the resulting array has the following formula.
=ARRAYFORMULA({'Source data'!A3:A,'Source data'!B3:B,IFERROR('Source data'!A3:A/0)})
This creates an array consisting of the two original columns A and B from the source data, plus an additional third column filled with blank values. This array can now be queried upon, and using the tricks previously provided by #basic the desired result as specified in the original question can be achieved.
Due to the query now being used upon a user-defined array, the columns in the SELECT statement now have to be referred to as Col1, Col2, Col3, instead of A, B, C. The final formula now looks like this.
=QUERY(ARRAYFORMULA({'Source data'!A3:A,'Source data'!B3:B,IFERROR('Source data'!A3:A/0)}),"SELECT Col1,Col2,'Test',Col3,'"&'Source data'!A1&"' WHERE Col1 IS NOT NULL LABEL 'Test' '','"&'Source data'!A1&"' ''")
I hope this information may prove of use to someone else as well.
I would appreciate some help, please.
I have a google sheet with many tabs with data going horizontally.
I would like to create a formula that imports and transposes the data into a vertical list.
However, I want to be able to type in (or drop-down list) to select the tab which the transpose formula to look at. I cannot get anything to work. I have tried this
=TRANSPOSE(A1&!B2:J2)
To add to that if it could use a lookup (vlookup or hlookup) to find the correct row to transpose then that would be great also.
I have set up a test sheet below. Please help. Many Thanks Tim https://docs.google.com/spreadsheets/d/1Menn6Z1mLl8wYOrcdQFnfs7Lp0dbC9UJe1S3AQRcOS0/edit#gid=0
You should not use IMPORTRANGE to work with data that exists anywhere in the same spreadsheet. IMPORTRANGE is for use retrieving data from a separate spreadsheet.
Instead, delete your current Sheet1!A2 formula and replace it with this:
=ArrayFormula(TRANSPOSE(INDIRECT(A1&"!B16:J16")))
I also added a new sheet ("Erik Help") with an advanced formula that accomplishes your lookup using whatever is types in B1. If whatever is typed in B1 exists in Column A of the selected sheet, the results of that row will be retrieved. If no match is found, IFERROR will return "No Match Found."
That formula, in 'Erik Help'!A2:
=ArrayFormula(IFERROR(QUERY(TRANSPOSE(INDIRECT(A1&"!B"&VLOOKUP("*"&B1&"*",{INDIRECT(A1&"!A:A"),ROW(INDIRECT(A1&"!A:A"))},2,FALSE)&":"&VLOOKUP("*"&B1&"*",{INDIRECT(A1&"!A:A"),ROW(INDIRECT(A1&"!A:A"))},2,FALSE))),"Select * WHERE Col1 Is Not Null"),"No Match Found"))
My Google Sheet that will be updated over time with new sheets. On my dashboard/master sheet, I can write a simple INDIRECT that will pull information from a cell in the sheets. However, the formula does not replicate its way down the column. I understand that I need to use an ARRAYFORMULA to get the auto formula placement done.
I've tried many ways but the one that I think may get me there is to use CONCAT. My columns look like this:
Event Title [uses a script to pull in the names of all the sheets]
Use an array to get the titles so they pre-poluate down the column so I can use it later: =ARRAYFORMULA(IF(Row(A:A)=1,"Get Title from A",IF(ISBLANK(A:A),"",A:A)))
-- The Event Title is now appearing as plain text in Column B.
I then use CONCAT to write the part of the formula I need to help get the name of the INDIRECT in without using the INDIRECT formula.
=CONCAT("'"&B5&"'"&CHAR(38)&"!"&"""","B2"&"""")
-- This gets me this result: 'Computers 101'&"B2"
At this point, my hope is that I could then use this information ('Computers 101'&"B2") into an ARRAYFORMULA. I used this formula to try and do that:
={"Event Date";ARRAYFORMULA(A6:A+D6:D&"Cat")}
-- I get the answer: 0
The expected value was the date cell (B2) in the Computers 101 sheet. Any ideas how to proceed? I don't know the names of the sheets in advance.
unfortunately, this is not possible within of scope of google sheets formula. if you need ranges from other than the actual sheet you need to use INDIRECT which is not supported under ARRAYFORMULA.
you have 3 options:
hardcode it like: https://stackoverflow.com/a/68446758/5632629 with IFERROR & array of empty cells to match columns of your range
generate formula which will generate your final formula/range as a text string and then use a simple script to convert that string into the valid formula: https://stackoverflow.com/a/61819704/5632629
do it all with scripts
I'm trying to create a spill-range solution to turn a list of dates and multiple columns of names into a structured two columns of data. I can do this using VBA, but because this will be automated and web-based, I need a spill-range solution.
A sample file of my situation can be found in this file.
As you'll see below, I have a list of a set of employees ("slackers") who have requested vacation/PTO during December. I've created a list of two spill range formulas that are:
A Column listing all days December
A list of slackers requesting the day off (array going horizontal).
Part 2 presents the problem as the the number of slackers is inconsistent and I'm not sure how to create additional dates for each row. Thus my problem is how to structure a filter/Array formula to list each employee, by day.
In the following tab, you can see my desired outcome. I've used a macro to generate this, but because this is web-based, I cannot use it.
I've tried a variety of mixing and matching array formulas and filters but cannot find a way to populate the date with each name.
While my question is scoped to addressing this conversion from multi-column to 2-column approach, I am happy to hear comments addressing the overall concept.
Here it is with your datatable:
=LET(
end, PtoRequestsTable[End],
strt, PtoRequestsTable[Start],
us, PtoRequestsTable[Slacker],
usCnt, COUNTA(us),
lst, DATE(YEAR(TODAY()),12,1),
led, DATE(YEAR(TODAY()),12,31),
dtSq, INT(SEQUENCE((led-lst+1)*usCnt,,lst,1/usCnt)),
md, MOD(SEQUENCE((led-lst+1)*usCnt,,0),usCnt)+1,
ussl, IF((INDEX(end,md)>=dtSq)*(INDEX(strt,md)<=dtSq),INDEX(us,md),""),
SORT(FILTER(CHOOSE({1,2},dtSq,ussl),ussl<>""),1,-1)
)
It will automatically grow and shrink with the table. It also has the start and end dates as inputs.
You may need to adjust maxWidth if there are more than 8 potential slackers.
=LET(maxWidth,8,
days,ByDay!A2#,
slackerBox,OFFSET(days,,1,,maxWidth),
ndx,SEQUENCE(ROWS(days)*maxWidth),
ndxDay,INT(ndx-1)/maxWidth+1,
slackerList,INDEX(slackerBox,ndxDay,MOD(ndx-1,maxWidth)+1),
FILTER(CHOOSE({1,2},INDEX(days,ndxDay),slackerList),slackerList<>0))