条件に合致する複数のレコードを請求データ一覧から取得し、請求書にリストアップする方法(マクロなし、MATCH関数を使用)
タイトル通りです。レコードを並び替える必要もありません。結構自信作かも。

イントロダクション
よく使われるVLOOKUP関数。早くて正確ですが、弱点があります。それは、検索結果を1件しか取り出せないことです。
例えば下の表には"りんご"を含む行が4つありますが、検索条件を "りんご"にして検索を実行すると、一番上の「りんご 2個」だけが取り出されます。ほかの3件を表示させる方法はないものでしょうか。

準備
それではまず、「請求書」シートと「請求データ」シートを用意します。

右の「請求データ」のA1:G21に「請求リスト」という名前を定義してください。
皆さんが作りたいものはそれぞれ異なるので、細かな作り込みの解説は割愛し、重要な部分だけを解説します。
種明かし
隠れた列や行に、数式を一時的に入れておく作業用のセルがあります。それらのセルに入っている数式を眺めてイメージをつかんでください。
下は、請求書シートのA列からD列の中身です。

次の要領で、各セルに名前を付けて下さい。
E2 顧客名 F2 請求月度 E4 最終行 F4 検索列 G4 検索値

A列には検索開始行が入ります。検索するのは「請求データシート」のE列です。
B列には検索範囲が入ります。「請求データシート」の検索範囲です。
C列には検索値が見つかった行が入ります。B列の「検索範囲」における位置です。
D列には検索値が見つかった行が入ります。「請求データシート」における位置です。
このD列の値、つまり、検索値が「請求データシート」の中で見つかった位置さえ分かれば、摘要や金額を取り出すことが可能になります。
もう一度、A列からD列に入っている式を見てみましょう

A列には、「請求データシート」から検索を開始する位置が入っています。1行目(A7)は当然「1」になります。もし、「請求データシート」の2行目で検索値が見つかったとすると、D1は2になり、A8は2+1で3になります。
このようにして、検索値が見つかった行+1を次の行の検索における開始行になるわけです。
B列は検索範囲が入ります。検索範囲は、検索列と、検索範囲(検索開始行と検索終了行)で構成されます。
このうち、検索開始行はA列を参照し、検索終了行は、「最終行 E3」を参照しています。
C列は、検索範囲において検索値が見つかった行位置を示します。ここではMATCH関数を使います。
MATCH関数は、ある範囲のなかで検索値が見つかった位置を返してくれます。
=MATCH(検索値, 検索範囲, 0)
最後の引数0は完全一致を指定する数値です

C列に実際に入力されている式は次の通りです。
=MATCH(検索値, INDIRECT(検索範囲を指す文字列), 0)
例えばC7に入っている式はこうです。
=MATCH(検索値(G4)、INDIRECT(検索範囲を指す文字列(B7)), 0)
D列の数値は、検索値が見つかった行が、請求書リストの先頭から何行目にあるかということを示しています。
今回は顧客名と請求月度の2つを検索キーにし、合計4通りの検索条件を設けることができるようにしました。

1. 両方が入力されている場合(AND検索) → E列を検索
2. いずれか一方だけが入力されている場合 → C列またはD列を検索
3. いずれも入力がない場合 → E列を検索
E列は顧客名と請求月度を連結しただけです。日付がシリアル値になっていますが、問題はありません。
ちなみに、検索値を入力する際に「Google」の代わりに「G*」や「*oo*」とワイルドカードを使っても同じ検索結果を得られます。MATCH関数って面白いですね。

あとは、検索値が見つかった行を基に、顧客名や摘要など各項目の値を参照するだけです。参照にはINDEX関数を使います。下は摘要を参照するための式です。検索値が見つからない場合は空白にします。
=IF(ISERROR(INDEX(請求データ, $D7, 6)), "", INDEX(請求データ, $D7, 6))
$D7には、検索値が見つかった行の行番号が入っています。6は請求データの6列目という意味です。
あとがき
前からこういうのをマクロ無しで作れないものかと、いろいろ試しては挫折していました。そんなに複雑な仕組みではないのですが、いろんな場面で応用できそうな気がします。