Conditional concatenate cell content across rows

Solution 1:

OK, took some head scratching, but I've got it:

Columns O, P & Q as you have them, titled Brand, Product & OEM. Turn the whole thing into a table with Ctrl-T (not required, but handy, and my column R relies on it, but you can use column references if you want)

Column R:

=IF(LEN([Brand])>0,[Brand],IF(LEN([Product])>0,[Product],IF(LEN([OEM])>0,[OEM],"")))

Column S:

=IF(A2=A4,F2&"/"&F3&"/"&F4,IF(A2=A1,"",IF(A2=A3,F2&"/"&F3,F2)))

Unfortunately, it seems the only way to use table references to a different row is to use Offset, so to keep it simpler, I went back to cell references. That kinda negates the cool/handy factor of turning the whole thing into a table in the first place, but, whatever...

And... Here's a picture of what it looks like:

enter image description here

Solution 2:

I would start by optimizing your O, P, and Q formulas.  You currently have

=IF(IFERROR(SEARCH("Brand is not valid", M42), "") <> "", "Brand", "")

IFERROR is a great function for displaying a sanitized version of a computed value that might be an error code; I use it, and recommend it in answers on Super User, frequently.  As you probably know,

  • IFERROR(calculated_value, default_value)

is short for

  • IF(ISERROR(calculated_value), default_value, calculated_value)

But using IFERROR to create a sanitized version of some value and then testing that value to do something conditionally is an unnecessarily awkward way of using IFERROR.  The above formula can be simplified to

=IF(ISERROR(SEARCH("Brand is not valid", M42)), "", "Brand")

And, as I’m sure you know, SEARCH("Brand is not valid", M42) tests to see whether M42 contains Brand is not valid.  But, as long as Column M can contain only your three error strings, this can be shortened to

=IF(ISERROR(SEARCH("Brand", M42)), "", "Brand")

or simplified to

=IF(M42 = "Brand is not valid", "Brand", "")

OK, now I’ll make the O, P, and Q formulas a little more complicated:

  • O42=IF($A42=$A41, O41, "") & IF(ISERROR(SEARCH("Brand", $M42)), "", "Brand")
  • P42=IF($A42=$A41, P41, "") & IF(ISERROR(SEARCH("Product", $M42)), "", "Product")
  • Q42=IF($A42=$A41, Q41, "") & IF(ISERROR(SEARCH("OEM", $M42)), "", "OEM")

The formula for O42 says,

If this is the second or third row for this ID (Column A), look at the cell above this one (i.e., the Column O cell for the previous row) to see whether we’ve already established that this thing has an invalid brand.  Also, look at Column M for this row to see whether it is Brand is not valid.  Then concatenate the results.

Since a unique ID will never be listed twice with the same error (right?), these two sub-results will never both be non-empty, so this is essentially doing an “OR”:

Show a value of Brand if this row, OR one of the previous row(s) for this ID, contains the invalid brand error.

This has the effect or dragging the O, P, and Q values down to the last row for each ID:

Note that rows 41, 44, 47, and 49 each shows the short forms of all errors that apply to their respective IDs in Columns O, P, and Q.

I’ve defined Column R the same way you did.  See Generate a comma-separated list of cell contents, excluding blanks for techniques to eliminate the unwanted slashes from this.

If having the desired concatenation only in rows 41, 44, 47, and 49 is good enough, you’re done.  Otherwise, define N42 as

=IF($A22=$A23, N23, R22)

or

=IF($A22<>$A23, R22, N23)

This is almost exactly the same trick I used in Columns O, P, and Q, but going in the opposite direction:

If this is the last row for this ID (i.e., if this is row 41, 44, 47, or 49), use the concatenation of the values from this row (which is the complete collection of error codes for this ID).  Otherwise, look at the cell below this one (i.e., the Column N cell for the next row), which will have the correct answer.

In other words, the desired values percolate up to the first row for each ID.