VLOOKUP with multiple criteria and multiple csv output - excel

I have two tables:
Table-A
List of regions and road types for each name (used letters for example)
Area Road Type Name
Masterton, Carterton LR A
Wairarapa LR B
Hamilton, Cambridge SH C
Auckland, Christchurch, Wellington LR,S D
NI SH E
SI SH F
NZ SH,LR G
Kapati, Levin LR H
Manawatu LR I
Napier SH J
Hastings, Havelock North SH,LR K
Hawke's bay LR L
Dunedin SH M
Napier LR N
NI LR O
Table-B
List of towns, provinces and islands (NI = North Island, SI - South Island)
Town Province Island
Masterton Wairarapa NI
Carterton Wairarapa NI
Hamilton Waikato NI
Cambridge Waikato NI
Auckland Auckland NI
Christchurch Canterbury SI
Wellington Wellington NI
Kapati Kapati Coast NI
Levin Horowhenua  NI
Napier Hawke's Bay NI
Hastings Hawke's Bay NI
Havelock North Hawke's Bay NI
Dunedin Otago SI
When you enter a Town into C2; C5, C6, and C7 will Vlookup Table-B to get the relevant data.
That's the easy bit.
What I am trying to do now is to get a list of names from Table-A (separated with a semi-colon) where either the town, province or island (from the vlookups) exists the in Area column and the Road Type (entered in C3) exists in the Road Type column.
Based on the input above the result would be: N; L; O
Can't seem to find an example of a vlookup that would provide the output
Any help would be greatly appreciated.
UPDATE:
My boss has hopefully made the solution a little simpler. Instead of the two tables, he has provided a single matrix showing:
Email T1 T2 T3 T4 T5 T6 T7 LR SH
A X X X
B X X X X
C X X X X X
D X X X X
E X X X X
F X X X X X
The T# represent a territory the user is interested in and one or both of LR and SH. So if the user provides a T# and either LH or SH the lookup needs to pick the email addressed where there is an X in the relevant T# column and an X in either LR or SH.
So, based on the table above:
T3 and LR would result in C, F
T1 and SH would result in B, F
T6 and LR would result in C, D
Not sure if this simplifies the solution or not.

Assuming that Table A is located at A3:D18, Table B is located at F3:H16 and the input Town and Road Type and the related Province, Island and Names are located at J3:N29.
To obtain the corresponding Province and Island, enter this formula in L4 and M4 then copy downwards:
=VLOOKUP( $J19, $F$3:$H$16, MATCH( L$3, $F$3:$H$3, 0 ), 0 )
To obtain the Names for the corresponding Town, Province and Island in one cell separated by ;, Enter this Array Formula in N4 then copy downwards:
Array Formulas must be confirmed by holding down CTRL + SHIFT + ENTER
=CONCATENATE(
IFERROR( INDEX( $D$3:$D$18, AGGREGATE( 15, 6, ROW($D:$D) / ( ( $D$3:$D$18 <> "" )
* IFERROR( SEARCH( $J19, $B$3:$B$18 ) > 0, NA() )
* IFERROR( SEARCH( $K19, $C$3:$C$18 ) > 0, NA() ) ), 1 ) ),"N/A"), "; ",
IFERROR( INDEX( $D$3:$D$18, AGGREGATE( 15, 6, ROW($D:$D) / ( ( $D$3:$D$18 <> "" )
* IFERROR( SEARCH( $L19, $B$3:$B$18 ) > 0, NA() )
* IFERROR( SEARCH( $K19, $C$3:$C$18 ) > 0, NA() ) ), 1 ) ), "N/A" ), "; ",
IFERROR( INDEX( $D$3:$D$18, AGGREGATE( 15, 6, ROW($D:$D) / ( ( $D$3:$D$18 <> "" )
* IFERROR( SEARCH( $M19, $B$3:$B$18 ) > 0, NA() )
* IFERROR( SEARCH( $K19, $C$3:$C$18 ) > 0, NA() ) ), 1 ) ), "N/A" ) )
The formula above returns N/A when the combination of Road Type and Town, Province or Island is not present in Table A.
Suggest to read the following pages for details about the functions used:
VLOOKUP function,
MATCH function,
CONCATENATE function,
IFERROR function,
INDEX function,
AGGREGATE function,
ROW function,
SEARCH, SEARCHB functions,
NA function

Related

Excel- cumulative sum of clusters in dynamic range

I have the dynamic range A (A#) and I want to calculate the cumulative sum of each "subrange" in B. The result musst be something as shown in column B. In other words I need a dynamic function/ formula which recognises the consecutive numbers in A und computes their total each time.
I only managed to solve this with a helper column C
C1: 1
C2: =IF(A1=A2,C1,C1+1)
C2 is draggable all the way down where you need it
B1: =IF(A1=A2,"",SUMIFS(A1,A1,A1))
B2: =IF(A2=A3,"",SUMIFS($A$1:A2,$C$1:C2,C2,$A$1:A2,A2))
B2 is draggable all the way down where you need it
With Office 365 you can use this LET to create a dynamic array that spills into Column B as you have shown:
=LET( a, A1#,
sa, SCAN( 0, a, LAMBDA(a,b, a + b ) ),
rSeq, SEQUENCE( ROWS( a ) ),
a_1, INDEX( a, rSeq + 1 ),
change, IFERROR( a_1 <> a, 1 ),
sChange, SCAN( 0, change*sa, LAMBDA(a,b, MAX( a, b ) ) ),
IF( change, sChange - IF( rSeq=1, 0, INDEX( sChange, rSeq - 1) ), "" ) )
where A1# is the input array.

Sqlite join columns on mapping of values

I want to be able to join two tables, where there is a mapping between the column values, rather than their values matching.
So rather than:
A|m | f B|m | f
a1 1 b1 1
a2 2 b2 3
a3 3 b3 5
SELECT a1, a2, b1, b2
FROM A
INNER JOIN B on B.f = A.f
giving:
|m| A.f B.f |m|
a1 1 1 b1
a3 3 3 b2
Given then mapping (1->a)(2->b)(3->c)
A|m | f B|m | f
a1 1 b1 a
a2 2 b2 b
a3 3 b3 c
to give when joined on f:
|m| A.f B.f |m|
a1 1 a b1
a3 3 c b2
The question below seems to be trying something similar, but they seem to want to change the column values, I just want the mappng to be part of the query, I don't want to change the column values thenselves. Besides it is in R and I'm working in Python.
Mapping column values
One solution is to create a temporary table of mappings AB:
CREATE TEMP TABLE AB (a TEXT, b TEXT, PRIMARY KEY(a, b));
Then insert mappings,
INSERT INTO temp.AB VALUES (1, "a"), (2, "b"), (3, "c");
or executemany with params.
Then select using intermediary table.
SELECT A.m AS Am, A.f AS Af, B.f AS Bf, B.m AS Bm
FROM A
LEFT JOIN temp.AB ON A.f=AB.a
LEFT JOIN B ON B.f=AB.b;
If you don't want to create an intermediary table, another solution would be building the query yourself.
mappings = ((1,'a'), (3,'c'))
sql = 'SELECT A.m AS Am, A.f AS Af, B.f AS Bf, B.m AS Bm FROM A, B WHERE ' \
+ ' OR '.join(['(A.f=? AND B.f=?)'] * len(mappings))
c.execute(sql, [i for m in mappings for i in m])

Extracting multiple numerical values from a carriage return-separated list in a cell

I have a table filled with cells formatted like this:
---(cell)---
3 x item
2 x another item
299 x yet another item
(... - variable amount of items here)
4 x the last item in this cell
---(end of cell)---
All items are separated with carriage returns (=CHAR(10)).
I need to extract the numbers and do various operations on them according to the item type. I'll take it one problem at a time and try to extract the numbers first. I'd use MID but it doesn't help with finding "the first set of numerical characters after a carriage return".
Any idea?
Here's a collection of formulas that will get you started. I have the cell to analyze as A1, and table of analysis results in B7:I11. The columns B-I are Item#, Start, End, SubString, Delim, Quantity and Item.
First, you can count the number of s in your cell
nCRs: =LEN($A$1)-LEN(SUBSTITUTE($A$1,CHAR(10),""))
The number of items is the number of CRs plus 1:
nItems: =LEN($A$1)-LEN(SUBSTITUTE($A$1,CHAR(10),""))+1
Note: to use the same tools on all items, I'm adding a CR to the beginning and end of the string. That way I'm always extracting sub-strings that are CR-delimited. To get the first item, put a 1 in B7:
B7: 1
To get the start of the first sub-string, use SEARCH with start pos = 1
C7: =SEARCH(CHAR(10),CHAR(10)&$A$1&CHAR(10),1)
Similarly get the end of the first sub-string with SEARCH starting to the right of where the first CR was found
D7: =SEARCH(CHAR(10),CHAR(10)&$A$1&CHAR(10),C7+1)
Now use MID to extract the text between two
E7: =MID(CHAR(10)&$A$1&CHAR(10),C7+1,D7-C7)
In F7 I have delimiter text (between item count and item description), assumed to be " x ":
F7: =" x "
In G7 find the location of the delimiter
G7: =SEARCH(F7,E7,1)
In H7 extract the text left of the delimiter (item count) and convert to a number
H7: =VALUE(LEFT(E7,G7-1))
In I7 extract the item description
I7: =RIGHT(E7,LEN(E7)-G7-LEN(F7)+1)
To get the second (and subsequent) items, start the search for CR where the last CR was found. So in C8
C8: =SEARCH(CHAR(10),CHAR(10)&$A$1&CHAR(10),D7)
Fill the formulas down to complete the table.
Hope that helps
This solution assumes data with text string containing multiple items per cell and separated by carriage returns is located in Sheet1 at B6:C11 as shown in figure 1 (adjust ranges in formulas as required).
Fig. 1
Objective as presented by OP:
I need to extract the numbers and do various operations on them
according to the item type. I'll take it one problem at a time and try
to extract the numbers first.
Yes, they're (numbers) always at the start of each carriage return, as
exemplified. What I need to do is stuff like "sum all numbers", "sum
all item A", "sum all item B" etc.
This solution proposes a review the objectives in order to first work on the extraction of the items to create a table with all items, after this is achieved then all other goals can be workout in a simpler manner.
First we add a column to the data in Sheet1. Enter this formula in C7 and copy till last record.
=SUM(1+LEN($B7),-LEN(SUBSTITUTE($B7,CHAR(10),"")))
Let’s create in Sheet2 a table to extract the items from the data in the Sheet1.
The extraction table is located at B6:G55 and contains the following items (see Fig. 2):
Itm.Nbr(+) : Enter this formula in B7 and copy till last record
=IF( OR( B6 = SUM( Sheet1!$C$6:$C$11 ), B6 = "" ), "",
- 1 + ROWS( B$6:B7 ) )
Line(+) : Enter this formula in B7 and copy till last record
=IF( EXACT( C6, C$6 ), 2,
IF( $B7 = "", "",
IF( $B7 <= SUM( INDEX( Sheet1!$C$6:$C$11, 1 ) : INDEX( Sheet1!$C$6:$C$11, C6 ) ), C6,
SUM( 1, C6 ) ) ) )
Itm.Lne(+) : Enter this formula in B7 and copy till last record
= IF( EXACT( D$6, D6 ), 1,
IF( $B7 = "", "",
IF( $C7 = $C6, SUM( 1, D6 ), 1 ) ) )
Extracted Lines(+) : Enter this formula in B7 and copy till last record
=IF( $B7 = "", "",
CLEAN( IF( $D7 = 1,
LEFT( INDEX( Sheet1!$B$6:$B$11, $C7 ),
FIND( CHAR(10), INDEX( Sheet1!$B$6:$B$11, $C7 ) ) ),
MID( LEFT( INDEX( Sheet1!$B$6:$B$11, $C7 ) & CHAR(10),
SEARCH( CHAR(135), SUBSTITUTE( INDEX( Sheet1!$B$6:$B$11, $C7 ) & CHAR(10), CHAR(10), CHAR(135), $D7 ) ) ),
SEARCH( CHAR(135), SUBSTITUTE( INDEX( Sheet1!$B$6:$B$11, $C7 ), CHAR(10), CHAR(135), - 1 + $D7 ) ), LEN( INDEX( Sheet1!$B$6:$B$11, $C7 ) ) ) ) ) )
Item : Enter this formula in B7 and copy till last record
=IF( $B7 = "", "",
IFERROR( MID( $E7, 3 + SEARCH( " x ", $E7 ), LEN( $E7 ) ), "!Err" ) )
Qty : Enter this formula in B7 and copy till last record
=IF( $B7 = "", "",
IFERROR( --TRIM( LEFT( $E7, FIND( " ", $E7 ) ) ), "!Err" ) )
(+) This working fields can be hidden
Fig. 2

Formula for finding vacancy percentage by month from check-in and check-out dates

I'm working on one spreadsheet. I want to find out total nights (month wise) from check-in and check-out date, Vacancy % (month wise), and Avg Night rate (month wise).
I've created simple format with google spreadsheet. Please check this https://docs.google.com/spreadsheets/d/1AZfpAic0PT3phLiedZh7I43pu6A3L9w4RhTchKtA0zw/edit#gid=0
In short, need to fill up "??" fields.
Assuming the sample data is located at C6:H63 (adjust as needed)
Note: Included three records at the beginning to show summaries for next year as well as error for monthly occupancy beyond monthly capacity.
This solution requires:
Two Working cells to provide flexibility and space for growth:
Capacity (rooms) : Located at E4; used to hold total numbers of rooms (actually is one, hopefully the business will growth).
Year : Year of the first period in Data, used to update header of “Monthly Allocation”, “Monthly Summary”. Located at K4
Total Nights : Modification of the formula to calculate Total Nights in column E in order to validated Check In & Check Out dates. Enter this formula in E7 and copy till last record:
=ISNUMBER( C7 ) * ISNUMBER( D7 ) * ( $D7 > $C7 ) * SUM( $D7, - $C7 )
The Results Range includes two areas (see Fig. 1)
Monthly Allocation : located at J6:V63
Header : Update Number Format for range J6:X6 as mmm-yy and Y6 as mmm dd, yyyy. Used to update the header of this area. Enter this formula in J6
=DATE( $K$4, 1, 1 )
And this formula in K6 and copy to L6:X6
= 1 + EOMONTH( J6, 0 )
Then enter this formula in Y6
=EOMONTH(X6,0)
Body : To allocate monthly occupancy enter this formula in J7 and copy till last record then copy to other months K7:X63
=IFERROR( IF( $E7 = 0, "", CHOOSE( 1
+ ( 1 + EOMONTH( $C7, -1 ) = J$6 ) * 1
+ AND( 1 + EOMONTH( $C7, -1 ) < J$6, 1 + EOMONTH( $D7, -1 ) > J$6 ) * 2
+ ( 1 + EOMONTH( $D7, -1 ) = J$6 ) * 3,
"",
1 + DAYS( EOMONTH( J$6, 0 ), $C7 ),
1 + DAYS( EOMONTH( J$6, 0 ), J$6 ),
DAYS( $D7, J$6 ),
SUM( $D7, - $C7 ) ) ),
"" )
Monthly Summary : located at I65:Y67
Total Nights : Enter this formula in J67 and copy tillY67`
=SUM( Y$7:Y$63 )
Vacancy % : Enter this formula in J65 and copy till Y65. This formula also validates the total occupancy against total capacity and returns !Err if occupancy > capacity (see Dec-15 in fig. 2).
=IF( J$67 > ( ( 1 + DAYS( EOMONTH( J$6, 0 ), J$6 ) ) * $E$4 ), "!Err",
1 - J$67 / ( ( 1 + DAYS( EOMONTH( J$6, 0 ), J$6 ) ) * $E$4 ) )
Avg Nightly Rate : Enter this formula in J66 and copy till X66
=SUMPRODUCT( J$7:J$63, $H$7:$H$63 )
and enter this formula in Y66
= 1 - $Y$67 / ( ( 1 + DAYS( $Y$6, $J$6 ) ) * $E$4 )
Fig. 1
Fig. 2
You need to allocate the days in each visit to the right month even when the visit is split over two months. I'm going to start by adding 12 helper columns with headers 1-12 (i.e. one per month) in columns I to T and use the following formula starting from I2 to find how many days to put in each month for each visit:-
=MAX(MIN(EOMONTH(DATE(2015,I$1,1),0)+1,$D2)-MAX(DATE(2015,I$1,1),$C2),0)
Then to get the vacancy percentage per month starting in V7 and pulled across:-
=(DAY(EOMONTH(DATE(2015,I$1,1),0))-SUM(I2:I55))*100/DAY(EOMONTH(DATE(2015,I$1,1),0))
To get the average room rate per month starting in V8 and pulled across:-
=ArrayFormula(iferror(SUM(I2:I55*$H2:$H55)/SUM(I2:I55),""))
And to get the total number of nights per month starting in V9 and pulled across:-
=sum(I2:I55)
Helper columns:-
Results:-

Look up formula works well except for one column

I have an excel file that has been uploaded here
http://www58.zippyshare.com/v/99974349/file.html
The formula works great except for a column with descending values.
=INDEX(
INDIRECT("'"&LOOKUP(B5,TblA)&"'!A6:A36"),
LOOKUP(9.99999999999999E+307,
SEARCH("-"&C8&"-","-"&INDIRECT("'"&LOOKUP(B5,TblA)&"'!C6:C36")&"-"),
ROW(C6:C36)-ROW(C6)+1))
Let me explain the excel file.
I have one main sheet 'Report' and 4 other sheets correspond to 4 age groups. - 4.2.0 to 4.7.30, 4.8.0 to 5.1.30, 5.2.0 to 5.7.30 and 5.8.0 to 6.1.30. Depending on the Age (B5) in the sheet 'Report', I select one of the 4 sheet to pick values from. I pick the correct sheet using a Table Name TblA which contains all sheet names and is defined from A24 to B27 in the sheet 'Report'.
In the sample sheet that is uploaded, B5 contains the value 5.7 which means we have to select the sheet 5.2.0 to 5.7.30.
Now from the sheet 5.2.0 to 5.7.30, I have to seek the respective Standard Score (1st column) for every Raw Score entered in 'Report'.
Here are the steps:
A. Enter Raw scores in sheet 'Report' C7 to C15
B. Search Respective sheet depending on age (B5 cell), in our case 5.2.0 to 5.7.30 since age is 5.7
C. Populate Standard score from Raw scores by picking the corresponding column in the 4 sheets. For example, if Raw Score of Col1 is 25 (C7), then pick the Standard score of Col1 from 5.2.0 to 5.7.30 and enter in D7 and so on.
D. This way all standard scores are filled in D7 to D15.
The formula works great except for D13 in sheet 'Report' since if you observe ColD in 5.2.0 to 5.7.30, it is in descending order.
How do I change the formula to accomodate this unique column?
Well, it's not really the order that's causing the error, it's because you don't have any results! The formula you use is trying to find -159- which it cannot find at all in the age sheet. You really need something to look into ranges, so that if you have 159, it will return a positive result when you try to match against 139-160.
I have made a formula building it from smaller ones, but when assembled, the repeating units make it daunting... Also, it's an array formula, so you need to use Ctrl+Shift+Enter for it to work as intended. You can still drag the formula down.
=INDEX(
INDIRECT("'"&LOOKUP($B$5,TblA)&"'!A6:A36"),
IFERROR(
MATCH(
C7,
INDEX(
INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),
0,
MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)
)*1,
0
),
MATCH(
1,
IF(
1*LEFT(
INDEX(
INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),
0,
MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)
),
FIND(
"-",
INDEX(
INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),
0,
MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)
)
)-1
)<=C7,
1,
0
)*
IF(
1*MID(
INDEX(
INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),
0,
MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)
),
FIND(
"-",
INDEX(
INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),
0,
MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)
)
)+1,
100
)>=C7,
1,
0
)
,0
)
)
)
The single line version...
=INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!A6:A36"),IFERROR(MATCH(C7,INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),0,MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0))*1,0),MATCH(1,IF(1*LEFT(INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),0,MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)),FIND("-",INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),0,MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)))-1)<=C7,1,0)*IF(1*MID(INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),0,MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)),FIND("-",INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),0,MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)))+1,100)>=C7,1,0),0)))
You can notice that there are some repeating blocks, namely:
INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36")
For the sheet name;
INDEX(
INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),
0,
MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)
)
Which is a larger block to make the formula a bit more flexible (it automatically picks the correct column e.g. if you change B8 Exclusion to Col1, the formula will automatically adjust itself)
If I call the first Sheet and the second Column, it becomes much shorter and perhaps easier to understand:
=INDEX(
Sheet,
IFERROR(
MATCH(
C7,
Column*1,
0
),
MATCH(
1,
IF(
1*LEFT(
Column,
FIND(
"-",
Column
)-1
)<=C7,
1,
0
)*
IF(
1*MID(
Column,
FIND(
"-",
Column
)+1,
100
)>=C7,
1,
0
)
,0
)
)
)
Or
=INDEX(Sheet,IFERROR(MATCH(C7,Column*1,0),MATCH(1,IF(1*LEFT(Column,FIND("-",Column)-1)<=C7,1,0)*IF(1*MID(Column,FIND("-",Column)+1,100)>=C7,1,0),0)))
Disclaimer: I'm not sure if there are any way to make this even shorter, but I guess that as long as it's working right now ^^
You can download your updated sheet here.
Explanation:
As I mentioned before, the formula is based off several smaller ones and quite a few repeats of those.
INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36")
As you already know (it's a variation of a part of your own formula), this gives the area containing all the different ages. Using it and the below, we get this:
INDEX(
INDIRECT('"&LOOKUP($B$5,TblA)&"'!B6:J36"),
0,
MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)
)
Into:
INDEX(
'Sheet'!B6:J36,
0,
MATCH(B7,'Sheet'!B5:J5,0)
)
Index will thus look into the range 'Sheet'!B6:J36, 0 indicates it will take any column(s) and MATCH(B7,'Sheet'!B5:J5,0) returns the nth column by taking the value of B7 (in the case of your spreadsheet, Col1) and looking it into 'Sheet'!B5:J5 which gives 1. The above will thus return the range 'Sheet'!B6:B36. Let's put it in the formula:
=INDEX(
'Sheet'!A6:A36,
IFERROR(
MATCH(
C7,
'Sheet'!B6:B36*1,
0
),
MATCH(
1,
IF(
1*LEFT(
'Sheet'!B6:B36,
FIND(
"-",
'Sheet'!B6:B36
)-1
)<=C7,
1,
0
)*
IF(
1*MID(
'Sheet'!B6:B36,
FIND(
"-",
'Sheet'!B6:B36
)+1,
100
)>=C7,
1,
0
)
,0
)
)
)
This formula is itself a giant INDEX formula, with range 'Sheet'!A6:A36 and row number as the big IFERROR group. The first part of the IFERROR() gets evaluated first:
MATCH(
C7,
'Sheet'!B6:B36*1,
0
)
This should be easy enough to understand. It looks for the raw score (from C7) into the range we obtained earlier, times 1 to convert everything to number (you can't look up numbers and text and expect a match). So that if there's an exact match of a number, it will return the row number of the found raw score and feed it to the INDEX(). For example, if the first row is returned, we get:
=INDEX('Sheet'!A6:A36,1)
Which is 'Sheet'!B6. If however there's no match (i.e. the raw score cannot be found), MATCH will return an error. And that's when the second part of the IFERROR comes into play:
MATCH(
1,
IF(
1*LEFT(
'Sheet'!B6:B36,
FIND(
"-",
'Sheet'!B6:B36
)-1
)<=C7,
1,
0
)*
IF(
1*MID(
'Sheet'!B6:B36,
FIND(
"-",
'Sheet'!B6:B36
)+1,
100
)>=C7,
1,
0
)
,0
)
This MATCH tries to find 1 within what seems to be two IFs; the first one being:
IF( 1*LEFT('Sheet'!B6:B36,FIND("-",'Sheet'!B6:B36)-1)<=C7 , 1 , 0)
FIND("-",'Sheet'!B6:B36)-1 gets the position of the last character before the - in the column 'Sheet'!B6:B36.
With those values, this FIND would return:
12-13 -> 2
145-155 -> 3
1567-1865 -> 4
The IF thus becomes:
IF( 1*LEFT('Sheet'!B6:B36,{2,3,4})<=C7 , 1 , 0)
Notice the braces here; they indicate an array and that's why this is an array formula. LEFT then extracts all the characters before the - (remember your other question, I answered with a technique very similar to this):
12-13 -> 2 -> 12
145-155 -> 3 -> 145
1567-1865 -> 4 -> 1567
Which is...
IF( 1*{12,145,1567}<=C7 , 1 , 0)
Again, 1* converts those to actual numbers because LEFT be default returns text characters. It's important here to do this because we're going to use the comparator <=, so that if the value to the left of C7 (the raw score), then the IF should return 1, else, it should return 0. Let's say that the raw score was 154. The results would be:
IF( {12,145,1567}<=154 , 1 , 0)
IF( {TRUE,TRUE,FALSE} , 1 , 0)
{1,1,0}
I just realised that the formula can be made a little shorter xD Anyway, we'll see that later. The next IF behaves in a similar fashion, but checks for the value at the right of the -:
IF( 1*MID('Sheet'!B6:B36,FIND("-",'Sheet'!B6:B36)+1,100)>=C7 , 1 , 0)
With...
FIND MID('Sheet'!B6:B36, X, 100)
12-13 -> 4 -> 13
145-155 -> 5 -> 155
1567-1865 -> 6 -> 1865
You can notice that this formula will stop working if you have something above 100 character long here. Anyway, the IF thus becomes:
IF( {13,155,1865}>=154 , 1 , 0)
IF( {FALSE,TRUE,TRUE} , 1 , 0)
{0,1,1}
Now that we have these, the MATCH from before becomes:
MATCH( 1 , {1,1,0}*{0,1,1} , 0)
Some simple math makes this into:
MATCH( 1 , {0,1,0} , 0)
And what is the position of the 1 in there? That's right, position 2!
Our original formula this becomes:
=INDEX( 'Sheet'!A6:A36 , IFERROR( #Error! , 2 ) )
So that if nothing was found at first, it will return an error (#N/A in this case) and instead return 2. =INDEX( 'Sheet'!A6:A36 , 2 ) gives 'Sheet'!A7.
And the slightly shorter version is:
=INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!A6:A36"),IFERROR(MATCH(C7,INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),0,MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0))*1,0),MATCH(1,(1*LEFT(INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),0,MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)),FIND("-",INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),0,MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)))-1)<=C7)*(1*MID(INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),0,MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)),FIND("-",INDEX(INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B6:J36"),0,MATCH(B7,INDIRECT("'"&LOOKUP($B$5,TblA)&"'!B5:J5"),0)))+1,100)>=C7),0)))
I actually removed the inner IFs, because (a>b)*(c>b) already returns 0s and 1s since TRUE multiplied by TRUE gives 1 in excel.
In Excel 2007 the formulae are returning a lot of circular reference warnings, so it may be worth adding a tag for your Excel version. Mine is Excel 2007 but with it the results you want seem achievable as below:
To shorten the formulae and reduce computation I have added in Report C5 "Table" and in D5 =VLOOKUP(B5,TblA,2,1).
I have also inserted a column immediately to the right of ColumnH ("ColD") in 5.2.0 to 5.7.30 and applied Text To Columns on Column H, with - as the delimiter.
I then applied to Report E7 and copied down to E15:
=INDEX(INDIRECT("'"&D$5&"'!A6:A36"),MATCH(C7,INDIRECT("'"&D$5&"'!"&CHAR(ROW()+59)&"6:"&CHAR(ROW()+59)&"36"),0))
and adjusted the 59s to 60s in the last three rows. Such adjustment would not be necessary if ColumnI were moved far enough to the right.
In E13 I changed the match from exact to next higher (final 0 to -1).
For Figures I cheated and changed K23 in 5.2.0 to 5.7.30 to 22 from 21-22, but such banding could, for other columns, be treated in much the same way as I did for ColD.

Resources