I've got a Dashboard which uses COUNTIFS and SUMIFS for the # and $ for transactions over multiple countries (columns) and that match certain criteria (rows).
Each row is split into different Fiscal Quarters and then breaks down into varies additional detail and months. The first row is 'everything', so the FQ Relative is ' * ', which works for strings in sum/countifs, but not for numerical, how can I use sum/countifs as a single formulae that can be copied down where the FQ can be zero, positive/negative numbers or a ' * ' (or something else) to represent anything.
The Dashboard is large so will need to repeat this multiple times, so it can't be a different formula (must be the same for each row).
Hopefully the below gives you a simplied view of what I'm working with.
ID | Caption | FQ Relative | FM | Other Criteria | Country A | Country B | Country C
1 | All Trans | * | * | <other criteria> | =sumif() | =sumif() | =sumif()
2 | Prev QTR | -1 | * | <other criteria> | =sumif() | =sumif() | =sumif()
3 | Current QTR | 0 | * | <other criteria> | =sumif() | =sumif() | =sumif()
4 | Next QTR | 1 | * | <other criteria> | =sumif() | =sumif() | =sumif()
Use a pair of < and > operators to provide a does not equal blank criteria for SUMIF/SUMIFS.
=sumifs(f:f, b:b, "<>")
This works against truly blank cells as well as cells that may contain a zero-length string (e.g. "") returned by a formula.
You can turn the numbers into text, and this should solve your issue.
If you're trying to do so in a more automated context, then this subroutine should work:
Sub TextifyNumbers(Block As range)
'This turns numbers into text so that they will work with the "*" wildcard
x = UBound(Block.Value, 1)
y = UBound(Block.Value, 2)
For i = 1 To x
For j = 1 To y
Block(i, j).Formula = Evaluate(Chr(34) & Block(i, j).Value & Chr(34))
Next j
Next i
End Sub
Related
I am trying to set up a table that will allow for very quick classification of sites across about 50 different characteristics. The method I have thought of but am unsure if it's possible is as follows.
Worksheet A: the raw data about 100R x 50C with each cell
describing a characteristic of that row where the last column is the
overall classification.
Worksheet B: a table of about 5R x 50C with the columns
corresponding to the columns in Worksheet A.
A row of Worksheet B would look something like:
* | * | * | 1 | * | 3 | * | Y | * | ... | * | * | * |
And a row from Worksheet A that corresponds with this data would look something like:
A | B | C | 1 | 5 | 3 | Z | Y | 1 | ... | F | 2 | X | High Priority
Where the asterisks indicate a wildcard where I don't care what the content is. All of the other cells would be required conditions. Then I was thinking of applying an array formula on the last column to get the classification. Something like:
{=IF(AND(A2:BV2='Worksheet B'!$A$2:$BV$2), "High Priority", "Low Priority")}
But Excel takes the asterisks as literal string content and evaluates it as FALSE.
Is there a way to make this work? Or an alternative method that would be just as simple to implement?
I got to the bottom of it with a reasonably elegant solution. Please post criticisms if there is a situation where this won't work.
={IF(SUM(IF(A2:BV2='Worksheet B'!A2:BV2,0,1))=COUNTIF('Worksheet B'!A2:BW2,"x"),"Top Priority", "Low Priority")}
Where x is for those cells in which I don't care about the outcome. So instead of "*", I am using "x" in the cells above such that Worksheet B is more like:
x | x | x | 1 | x | 3 | x | Y | x | ... | x | x | x |
If anyone is interested, the formula works by counting all of the mismatched elements and checking them against the number of cells with "x" in the result. If these two numbers are equal, the number of mismatches is equal to the number of cells we don't care about.
I am trying to create a formula in a spreadsheet which has several thousand lines. I am struggling with the part where I need to find out how many children (y) does parent (x) have - counting value until value changes.
I've tried using =IF(A2=OFFSET(A2,-1,0),OFFSET(B2,-1,0)+1,1) which currently gives count to child products.
The ultimate goal would be to output values of all children based on the count.
+---+------+-------+-------+--------------+--+
| 1 | Type | Count | Value | Child Values | |
+---+------+-------+-------+--------------+--+
| 2 | x | 1 | A | B | |
| 3 | y | | B | | |
| 4 | x | 2 | C | D,E | |
| 5 | y | | D | | |
| 6 | y | | E | | |
| 7 | x | 1 | F | G | |
| 8 | y | | G | | |
+---+------+-------+-------+--------------+--+
So if x has 2 children, then the formula would output values of next 2 cells next to it (Child Values). The parents can have up to 8 children and would need to take a number of next cell values based on count.
Is this second part even possible without Excel VBA? I appreciate your help!
This may not be the best answer, but it does avoid VBA. You do have to have a dummy x with no children at the bottom of the list.
Your count formula is:
=IF(A2="y","",MATCH("x",INDEX($A:$A,ROW()+1):INDEX($A:$A,COUNTA($A:$A)),0)-1)
INDEX($A:$A,ROW()+1):INDEX($A:$A,COUNTA($A:$A) will set a reference from the next row down to the end of the list providing there is a value in every cell in column A from A1 to the end of list.
MATCH("x",....,0) will return the row number in the referenced range that the next x occurs on. Minus one from this will give the number of children for the x.
IF(A2="y","",.......) makes sure the count only appears on the x rows.
As you'll only have a maximum of 8 children you could use this formula to return the Child Values.
=IF(B2="","",CONCATENATE(IF(B2>=1,C3,""),IF(B2>=2," ," & C4,""),IF(B2>=3," ," & C5,""),IF(B2>=4," ," & C6,""),IF(B2>=5," ," & C7,""),IF(B2>=6," ," & C8,""),IF(B2>=7," ," & C9,""),IF(B2>=8," ," & C10,"")))
Ok, so I have some data that I want to convert from multiple rows to multiple columns.
My input data looks loosely like this -
+----------+----------------+-----------------+
| SKU | Attribute Name | Attribute Value |
+----------+----------------+-----------------+
| Product1 | Colour | Black |
| Product1 | Size | Large |
| Product1 | Height | 20cm |
| Product1 | Width | 40cm |
| Product2 | Colour | Red |
| Product2 | Width | 30cm |
| Product2 | Size | Large |
| Product3 | Height | 25cm |
| Product3 | Width | 30cm |
| Product3 | Length | 90cm |
| Product3 | Weight | 5kg |
| Product3 | Size | Large |
| Product3 | Colour | Blue |
+----------+----------------+-----------------+
What I want to achieve is an output like this -
+----------+--------+--------+--------+-------+--------+-------+
| SKU | Colour | Height | Length | Size | Weight | Width |
+----------+--------+--------+--------+-------+--------+-------+
| Product1 | Black | 20cm | | Large | | 40cm |
| Product2 | Red | | | Large | | 30cm |
| Product3 | Blue | 25cm | 90cm | Large | 5kg | 30cm |
+----------+--------+--------+--------+-------+--------+-------+
I've tried Pivot tables, but you can only return numeric values, rather than the text values I'm looking for.
I know I could probably achieve it using a number of step looking up values and filling them, but I feel like there should be a more simplistic way to achieve this. Maybe it's something better achieved in database rather than a spreadsheet.
Any help would be very much appreciated.
You can do this in ̶5̶ ̶s̶t̶e̶p̶s̶ 4 steps with Powerquery. This is in-built for 2016 and a free add-in from Microsoft from 2013 on wards ( or 2010 Professional Plus with Software Assurance). See info https://www.microsoft.com/en-gb/download/details.aspx?id=39379
The advantage is you can easily add rows to the source and simply refresh the query.
1) You select any cell in the range, then in 2016 Get & Transform tab, earlier version use the Powerquery tab, select data from table. A window will pop up with your range of data in:
2) Transform > Pivot column > Attribute Name column for Attribute Value in Values Column (used advanced options to select "Don't aggregate")
3) Drag columns around to desired arrangement
4) Home > Close and load to sheet
Here is a version without the column re-ordering
Edit:
Thanks to #Ron Rosenfeld for reminding me that truly null values don't need replacing with blanks as they will appear as blanks when written to the sheet.
So this step was removed:
4) Highlight columns to replace nulls in and go to transform > replace values > and
Value to Find: null
Replace With:
You could do this using a helper column and then match it using index + match. Not as simple as you thought, but does work.
1) Add helper column to your data (call it 'Helper'). =concat(SKU,'Attribute Name')
2) Use a pivot to get a unique list of SKUs in the rows so that it's easy to update once the data changes. (I'm assuming this is in column A and values start at row 4).
3) Use another pivot to get a unique list of Attributes in the columns next to the other pivot. Then you have the structure of your results. (I'm assuming the first value is in B3).
4) Index match the values of the table =index('Attribute Value', match(concat($A4,B$3),'Helper',0))
Note though that this only works when each combination of SKU and Attribute is unique.
This assumes that the data is in columns A through C:
Sub croupier()
Dim i As Long, N As Long, vA As String, vB As String, vC As String
Dim rw As Long, cl As Long
' setup column headers
Columns(2).SpecialCells(2).Offset(1).Copy Range("D1")
Columns(4).RemoveDuplicates Columns:=1, Header:=xlNo
Columns(4).SpecialCells(2).Copy
Range("E1").PasteSpecial Transpose:=True
Columns(4).SpecialCells(2).Clear
' setup row headers
Columns(1).SpecialCells(2).Copy Range("D1")
Columns(4).RemoveDuplicates Columns:=1, Header:=xlYes
' deal the data
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = 2 To N
vA = Cells(i, 1)
vB = Cells(i, 2)
vC = Cells(i, 3)
cl = Rows(1).Find(what:=vB, after:=Range("A1")).Column
rw = Columns(4).Find(what:=vA, after:=Range("D1")).Row
Cells(rw, cl) = vC
Next i
End Sub
I have a worksheet with the following info:
| A | B | C |
| 10 | cat | |
| 15 | cat | |
| 5 | dog | |
| 4 | dog | |
| 11 | dog | |
| 6 | fish | |
| 10 | fish | |
I want to find out which is the maximum value in the A column by grouping them according to the value into the B column. That is, the max value for cat, for dog and for fish.
I was thinking about using the function FormulaArray with Max and If functions:
mysheet.range("C1:C7").FormulaArray="=Max(If(R1C2:R7C2=RC[-1],R1C1:R7C1))"
i tested it but it doesnt work, this formula only compares the first element (B1) with the whole range (B1:B7).
Is there any better answer?
You could use a combination of MAX and INDEX like this:
Array formulas can return single results or multiple results. You want yours to return a single result for each cell in your range, but since you're applying the array formula to the entire range, it is being interpreted as a single formula returning multiple results over the entire range instead of a single formula for each cell.
You can test this by changing something in your array range. Say, change the ",0)" to ",1)" in C3. It will tell you you can't change a part of an array. They're all connected.
What you need to do is loop through the cells in your range and apply the formula to each of them.
Dim r As Range
Dim rFormulas As Range
Set rFormulas = ActiveSheet.Range("C2:C8")
For Each r In rFormulas.Cells
r.FormulaArray = "=MAX(IF(R2C2:R8C2=RC2,R2C1:R8C1,0))"
Next r
I have a row of random data in Excel like below:
| A | B | C | D | E | F | G |
| 1 | see | saw | swing | see | slide | | |
How could I detect if there were duplicates in row 1 and return a 1 if there were and a 0 if there were not, ignoring any blank cells in columns F and G?
This array formula works:
=OR(COUNTIF($A$1:$G$1,A1:G1)>1)
Array formulas are entered using Ctrl + Shift + Enter instead of regular Enter
If 0 or 1 is needed, add 2 hyphens at the beginning of the formula:
=--OR(COUNTIF($A$1:$G$1,A1:G1)>1)
I ended up using:
=(COUNTIF(A1:G1,A1)>1)*1