見出し画像

Googleスプレッドシート QUERY関数 超応用例 10(where句 徹底解析4)

Googleスプレッドシートの最強集計関数 QUERY関数について書いたnoteの第10回です。

前回に続き QUERY関数のwhere句を掘り下げていきます。where句だけで4回もやってますw

👇これまでのQUERY関数シリーズは マガジンにまとめています。QUERY関数をハイレベル(廃レベル)に使いこなしたい人は必読です!

前回はQUERY関数の where句 徹底解析3 で、where句で使える文字列演算子の使い方を紹介しました。




where句を極める

今回は前回以上にディープな where句の活用に入っていきます。前回の最後に触れた、以下について書いていきます。

✅メタ文字を「含む」条件で利用したい場合の記述

✅セル内改行ありの列を対象とした場合の「含む」条件

✅REGEX系関数で使える 正規表現と違って QUERY関数の matchesの正規表現は「先読み」「後読み」が使える!?

✅複数列の一致や含むの長いクエリ文の記述を生成する方法

さすがにここまでディープなQUERY関数 where句の解説は、他には無いと思いますw(役に立つかどうかは微妙ですが)



覚えるべき 文字列比較演算子は?

QUERY関数のクエリ文は 11の言語句があって、さらに列を加工する14のスカラー関数5つの集計関数があって、 where句にも 5つの文字列比較演算子があって・・・。

覚えることどんだけ~!!って思いますよね。

mirのnoteではQUERY関数を完全網羅していきますが、もちろん全部を覚える必要はなくて、この中から必要なもの・よく使うものだけをしっかり理解して活用していくことが大事です。

文字列比較演算子も 5つ登場しましたが、もし正規表現を理解しているのであれば、他の4つは捨てて matchesだけ使う でも良いでしょう。

matches と正規表現が使いこなせれば、前方一致、後方一致、含む、複雑な条件での判定 が可能となり、他の文字列比較演算子をすべて代替できます。

じゃあ正規表現を知らないユーザーは、matches の次に自由度の高い like が使えれば良いか?というと、実はそうでもありません。

likeではどうしても条件記述出来ないパターンが 大きく2つあります。  



where句でメタ文字を「含む」条件で利用したい場合の記述

文字列比較演算子 like の弱点の一つが、メタ文字を指定した「含む」検索が出来ないことです。

※メタ文字とは、特殊な意味合いを持つ文字のことです



like は % や _ をエスケープできない

たとえば where句の 文字列演算子 like を使った際、その後の'(シングルクォート)で括られた文字列の中で登場する %_ はそれぞれ

% 任意の0文字以上の文字列
_  任意の1文字

という意味を表すメタ文字です。

では、

このようなデータがあった時、 % という文字を含むデータ(2、4、7)をQUERY関数で抽出したい場合はどうすればよいか?

ここで like しか使えない人は詰みます

 なぜならQUERY関数の like のワイルドカード(% や _ )には、エスケープが存在しないからです。

シート関数の COUNTIFやVLOOKUP などで使用できるワイルドカード * や ? は ~(チルダ)を前につけることでエスケープできます

=COUNTIF(A2:A3,"*~**")

*という記号を含むセルをカウント

このようなエスケープ記法が、QUERY関数の likeには存在しない、つまり likeでは % や _ を通常の文字として扱うことができないってことです。

ちなみに MySQL のクエリ文の like では  \ (バックスラッシュ)でエスケープ出来るようですが、残念ながらQUERY関数では機能しません。

※ QUERY関数の like にもエスケープがあるという場合はお知らせください


というわけで、 % や _ を含む という条件を QUERY関数で使いたい場合は like を使うのではなく、

=QUERY(A:C,"where Col2 contains '%'")

contains を使って記述するか

=QUERY(A:A,"where Col1 matches '.*_.*'",0)

_ を含むという条件

matches で正規表現を使う 必要があるってことです。

まぁ滅多にないケースですけどね。



matches の正規表現は \(バックスラッシュ)でエスケープできる

like にはメタ文字をエスケープできない という弱点がありましたが、matches は その点においては死角はありません!

正規表現は \(バックスラッシュ)を頭につけることで、次の文字をエスケープ(そのままの文字として扱うことが)できます。

たとえば 正規表現では、* は 前の単語の 0回以上の繰り返しを意味しますが、この *を含む文字列をQUERY関数 matchesで抽出したい場合は

 =QUERY(A:A,"where Col1 matches '.*\*.*'",0)

このような記述になります。

'.*\*.*'

わかりづらいですが、これは 真ん中の \で エスケープした * という文字の前後 に .*(任意の文字の0回以上の繰り返し) を置くことで、 * を含むセルにヒットさせる(TRUEを返す)としています。

しっかり * を含むデータだけを抽出出来ています。

matches は使いこなせれば最強ってことです。



Q1. '(シングルクォート)や "(ダブルクォート)を含むを条件として抽出したい

それでは違うメタ文字を条件とするお題にチャレンジしてみましょう!

クエリ文の中で "(ダブルクォート)' (シングルクォート)を そのまま文字として where句の 含む条件で利用したい!

こんな時はどうすればよいか?これをお題にします。

データは 👇を A1セルに貼って利用ください。

No	メモ
1	この記号 "は ダブルクォートです
2	この記号 ' は シングルクォートです。
3	クォーテーションとも言います
4	セル内で"で括った文字は文字列化します
5	クエリ文で 'で括った文字はリテラルとして扱われます

このデータの2列目に ”(ダブルクォート)を含んでいるデータ、'(シングルクォート)を含んでいるデータの抽出をしたい場合、それぞれQUERY関数でどんな式を作ればよいか?

考えてみましょう!








↓↓
回答はここから。

↓↓





A1. '(シングルクォート)や "(ダブルクォート)を含むを条件として抽出する

回答です。

2列目に ”(ダブルクォート)を含む
=QUERY(A:B,"where Col2 contains '""'")

2列目に '(シングルクォート)を含む
=QUERY(A:B,"where Col2 contains ""'""")

うーん、見た感じよくわからないですよねw 解説を入れると

「ダブルクォートを含む」を条件とする場合
「シングルクォート」を含むを条件とする場合

このようになっています。

ダブルクォートは 文字列内で "" と 2連発することで " という文字として扱えることを利用しています。

また「シングルクォートを含む」を条件とする方は、通常は条件に使う文字リテラルをシングルクォートで括るところを ダブルクォートで括ることによって、その中の '(シングルクォート)を 文字として扱っています。

ん?クエリ文内の 文字リテラルは ' シングルクォートで括るってルールじゃないの??と思うかもしれませんが、実は公式にも

このように

string リテラルは一重引用符または二重引用符で囲む必要があります。

https://developers.google.com/chart/interactive/docs/querylanguage?hl=ja#literals

と、どちらでも良いと書いてあります。

通常はQUERY関数の第2引数のクエリ文は全体が ”(ダブルクォート)で括られている為、その中で使える '(シングルクォート)を使っているだけなんです。

このようなシングルクォートを 条件として利用したい 特殊なケースでは ダブルクォートで括って 文字リテラル化する方法もあるってことです。

ただし、これも滅多に無いケースなんで覚えるというよりは、こんなケースがあったらこのページに戻ってくれば良いです。



セル内改行ありの列を対象とした場合の「含む」条件

mirのnoteで紹介した QUERY関数では、ここまではセル内改行の無いデータを扱ってきました。

しかし、実際の運用ではセル内改行のあるデータを扱うこともあります。

たとえば 👆こんなデータがあったとします。

No	メンバー	掃除箇所
1	"山田
鈴木
田中"	廊下
2	"松尾
片野
平方"	椅子
3	"鈴木
加藤
和田"	机
4	"北村
川島"	トイレ
5	"多田
飯島
鈴木"	体育館

このようなセル内改行のあるデータも QUERY関数で扱えるんですが、注意するポイントがあります。



like はセル内改行のあるデータを扱えない

セル内改行があるデータを対象といた場合でも、 「含む」条件による抽出は可能です。

たとえば contains を使って E1セルのメンバー名 を 2列目(メンバー)に含むデータを抽出したい場合は

=QUERY(A:C,"where Col2 contains '"&E1&"'")

こんな式で E1(鈴木)を含む 1,3,5のデータを出力することが出来ます。

しかし、これを likeを使って記述しても

=QUERY(A:C,"where Col2 like '%"&E1&"%'")

このように 1件もヒットしません。

理由は likeのワイルドカードである % や _ は改行を対象外とする為です。

 改行なしのデータであれば like '%鈴木%' は 鈴木を含む行でTRUEとなりますが、改行入りのデータを対象とすると機能しません。

%や_ といったワイルドカードは任意の文字を表すとなっていますが、正しくは 改行以外の任意の文字ってことです。

※COUNTIFやVLOOKUPで利用できる ワイルドカード * や ? は改行にもヒットします。

セル内改行ありのデータ(列)に対して where 句で含む や前方一致、後方一致を 条件として使いたい場合は、contains、starts with、 ends with を使いましょう。

 これが  like で記述できないケースの2つ目です。



Q2. matches を セル内改行のあるデータに対して使いたい

では、改行ありのデータを matches の正規表現で扱う場合はどうしたらよいでしょうか?

通常の書き方

=QUERY(A:C,"where Col2 matches '.*"&E1&".*'")

だと1件もヒットしません。 これは .(ドット)が 改行を対象としない(マッチしない)為です。

では、どう記述すればよいか?これをお題としてみましょう。正規表現を知ってる人には簡単ですね。

考えてみましょう!








↓↓
回答はここから。

↓↓





A2. matches を セル内改行のあるデータに対して使う

回答です。

=QUERY(A:C,"where Col2 matches '[\s\S]*"&E1&"[\s\S]*'")

.(ドット)の代わりに [\s\S]を使って 

'[\s\S]*"&E1&"[\s\S]*'

このように記述します。これが 改行ありのデータに対して使える E1セルの文字を含む 条件で抽出する記述です。

中身は

\s 空白文字(スペース、タブ、改行)にマッチ
\S 空白文字以外すべての文字にマッチ

このような意味です。よって、1文字単語いずれかを表す [\s\S]

[\s\S] 改行を含むすべての文字にマッチ

する1文字という意味になります。この記述も覚えておいて損はないでしょう。

ちなみに、これだと cotains 使った方が簡単ですが、matches で正規表現を使うことで、 contains、 starts with、 ends with では拾えない 先頭や末尾ではなく、改行のあるデータの 途中にキーワードが出てくるケース だけを条件にすることも出来ます。

=QUERY(A:C,"where Col2 matches '[\s\S]+"&E1&"[\s\S]+'")

👆 先ほどは [\s\S]*(改行を含む任意の文字の0回以上の繰り返し) としていた箇所を [\s\S]+ (改行を含む任意の文字の1回以上の繰り返し)に変えることで E1の前、後ろになにかしら1文字以上あるセルにだけマッチさせています。

これで改行入りデータをQUERY関数 where句で扱う時の書き方も理解できましたね!



QUERY関数の matchesの正規表現は「先読み」「後読み」が使える!?

Googleスプレッドシートでは、

  • REGEX系関数(REGEXMATCH、REGEXEXTRACT、REGEXREPLACE)

  • QUERY関数 (matches)

大きくこの2つの関数系統で 正規表現が使えるんですが、実は REGEX系関数と QUERY関数(の matches)では、使える正規表現に違いがあります。



REGEX系関数 と QUERY関数の 使える正規表現の違い

REGEX系関数とQUERY関数で扱える正規表現の違いですが、大きな違いとしては以下の2点があります。

✅シングルラインモード、マルチラインモード
 REGEX系関数・・・ 使える
 QUERY関数 matches・・・ 使えない

✅先読み、後読み
 REGEX系関数・・・ 使えない
 QUERY関数 matches・・・ 使える

シングルラインモードは (?s) を正規表現の頭に付けることで、通常は .(ドット) ではマッチしない改行を . でマッチできるようにする記述です。.(ドット)が全てにマッチするので、ドットオールモードとも言います。

https://note.com/mir4545/n/nc7598f6509bb#54c317d6-21bc-4bde-8608-f4a01ce4ace8

一方マルチラインモード (?m) は、スプレッドシートで利用する場合は セル内改行のある文字列に対して、改行単位で個々の行 の先頭と末尾を ^ $ にマッチさせる記述です。

https://note.com/mir4545/n/n5fb2bafaf329#827569a4-cb9c-4a73-bd3e-a60185dc3a3f

シングルラインモードが使えたら先ほどの改行ありの含む条件も

× =QUERY(A:C,"where Col2 matches '(?s).*"&E1&".*'")

こんな記述で書けるんですが、残念ながらコレはつかえないってことです。

この2つのモードについては、REGEX系関数の回で改めて紹介したいと思います。


一方 QUERY関数の matches の正規表現では、REGEX系関数では使えない 先読み、後読みが使えます

先読みと後読みは 少し複雑なパターンマッチの記述なので、今回は他のサイトを参照くださいってことで説明は割愛します。

とりあえず、QUERY関数 matches の正規表現は REGEX系関数の正規表現とは少し違って、「検索と置換」機能で使える正規表現に近い と言えます。

さらに言えば、 Googleスプレッドシートで、正規表現の 先読み・後読みが使える関数 は、QUERY関数 だけ ってことです!(ExcelのREGEX系関数だと使えるんでぐぬぬぬ・・ってなります)


ただし 先読み、後読み 非常に便利なんですが、記述が複雑ですし、そもそも QUERY関数の matches で扱う正規表現は 全文一致 でTRUE、FALSEを返すものなので、活用シーンは限られます。

その中でも QUERY関数 matches で正規表現の先読みを使った便利なネタを紹介しておきましょう。



Q3. 複数のキーワードを全て含むを条件として抽出したい

お題形式でいきます。

👇こんな感じの Googleフォームで集計した フルーツに関するアンケート結果が という名前のテーブルデータとしてまとまっています。

フルーツの印象(5列目)は、Googleフォームのチェックボックス質問で複数回答したものが

", " (カンマ+半角スペース)区切り

で入っています。

ここから

このように G1,H1,I1 の3つのセルに入れたキーワードを フルーツの印象(5列目)に全て含むデータを抽出したい場合、どのような式を作ればよいでしょうか? 改行を考慮する必要はありません。

※前回は複数選択プルダウンのお題だったんで、今回はキーワードのセルを分けるパターンにしてみました。

キーワードは 0~3個指定するものとして、0個(全て空白セル)の場合は、全データ出力とします。

データはコチラを利用ください。 👇(テーブル名は 表 としています)

回答ナンバー	性別	年齢	好きなフルーツ	好きなフルーツの印象
1	女性	25	りんご	美味しい, ジューシー, 食べやすい
2	男性	38	バナナ	美味しい, リーズナブル, 食べやすい
3	女性	19	いちご	甘い, 美味しい, ジューシー
4	男性	45	みかん	甘い, 美味しい, 食べやすい
5	女性	31	ぶどう	甘い, 美味しい, 高級感がある, ジューシー
6	男性	28	スイカ	甘い, 美味しい, ジューシー
7	女性	22	メロン	甘い, 美味しい, 高級感がある
8	男性	52	キウイ	美味しい, 食べやすい, 香りがよい
9	女性	29	桃	甘い, 美味しい, ジューシー
10	男性	35	梨	美味しい, ジューシー, 食べやすい
11	女性	27	マンゴー	甘い, 美味しい, 高級感がある, ジューシー
12	男性	41	パイナップル	甘い, 美味しい, ジューシー
13	女性	23	さくらんぼ	甘い, 美味しい, 高級感がある
14	男性	48	柿	甘い, 美味しい, 食べやすい
15	女性	33	レモン	ジューシー, 香りがよい
16	男性	39	グレープフルーツ	美味しい, ジューシー
17	女性	26	ブルーベリー	甘い, 美味しい, 食べやすい
18	男性	55	アボカド	美味しい, 高級感がある
19	女性	21	ラズベリー	甘い, 美味しい, ジューシー
20	男性	37	ライチ	甘い, 美味しい, ジューシー, 香りがよい

QUERY関数で式は作れなくても FILTER関数なら出来る!って場合は、FITER関数で作ってみてもよいです。

これは超応用例の部類です。
自信のある人だけチャレンジしてみてください!








↓↓
回答はここから。

↓↓





A3. 複数のキーワードを全て含むを条件として抽出する(QUERY関数 正規表現)

回答です。

=QUERY(表[#ALL],"where Col5 matches
'(?=."&TEXTJOIN(")(?=.",TRUE,G1:I1)&").*'")

よくわからないですよね?

これは matches の後ろの条件記述だけ取り出して

="'(?=."&TEXTJOIN(")(?=.",TRUE,G1:I1)&").*'"

とするとわかりますが、

'(?=.*ジューシー)(?=.*高級感がある).*'

こんな文字列を生成しています。

(?=パターン) は正規表現の 先読みの記述なんですが、

(?=.*A)(?=.*B)(?=.*C).*

という書き方をすることで、順番に依らず「A、B、C を全て含む」文字列にマッチさせることが出来ます。

この記述を生成している核が TEXTJOIN(")(?=.",TRUE,G1:I1) この部分です。

あとは頭に "'(?=." お尻に ").*'" を付ければOKですね。

ちなみにキーワードが空だった場合は、

matches の後ろは '(?=.*).*' このようになり、これは 空白を含めた全てのセルにマッチするので 全データ出力となります。

(?=.*A)(?=.*B)(?=.*C).* なぜ 「A、B、C を全て含む」 を表すのか?は難しいのでここでは触れません。

気になる人はAIに聞くと詳しく教えてくれます



A3(別解). 複数のキーワードを全て含むを条件として抽出する(FILTER関数)

オマケで QUERY関数で正規表現で回答するのはわからなかったけど、FILTER関数なら出来た!って人用の回答例です。

=FILTER(表,BYROW(REGEXMATCH(表[好きなフルーツの印象],G1:I1),
LAMBDA(r,AND(r))))

回答の一例です

以前はMMULTあたりをからめて対応するケースですが、現在はBYROWで行毎に AND関数しちゃうのが簡単ですね。

難しかったかもしれませんが、QUERY関数の matchesの正規表現が 先読みを使えることを活かした 実務で使える例です。

stack overflowでも最近コレが使える質問が入ってました。(さすがに mirも海外サイトに遠征して回答したりはしませんがw)

https://stackoverflow.com/questions/79650251/google-sheets-filter-on-regexmatch-and-condition



否定先読みで「全て 含まない」を条件に抽出する (でも not で出来る)

もう1つ 否定先読み (?!パターン) を使った、複数キーワードを「全て含まない」という条件記述を紹介しておきます。

ただ、こちらは覚える必要はありません。お題にはしませんので、参考程度に見といてください。

「食べやすい」「甘い」「ジューシー」のいずれも含まない

=QUERY(表[#ALL],"where Col5 matches
'(?!.("&TEXTJOIN("|",TRUE,G1:I1)&")).'")

先ほどと同じように TEXTJOIN関数を使って 正規表現の否定先読みで 含まないの記述を生成しています。


="'(?!.("&TEXTJOIN("|",TRUE,G1:I1)&")).'"

で確認すると

'(?!.*(食べやすい|甘い|ジューシー)).*'

このような文字列が生成されています。

つまり (?!.*(A|B|C)).* これが 「A、B、Cのいずれも含まない」という記述になります。

でも、前回これだけは覚えて!で 

✅複数の値のいずれかを「含む」という条件の記述
matches '.*(apple|car|free|zoo).*'

を紹介しましたが、実は これに論理演算子の not を組み合わせれば

=QUERY(表[#ALL],"where not Col5 matches
'.("&TEXTJOIN("|",TRUE,G1:I1)&").'")

いずれも含まないという条件記述は 簡単に出来ちゃうんですよね。

だから、否定先読みによる「いずれも含まない」って条件の書き方は、QUERY関数で使う必要はなさそうです。



QUERY関数の 複数列の一致や含むの長いクエリ文の記述を生成する

最後に 実用性の高い、複数列に対して and で 一致や 含む条件の記述を 数式で生成する応用例を学んで終了としましょう。

データは前回も使った sampleテーブルを使います。

氏名	ふりがな	性別	年齢	血液型	住所	既婚
佐藤 健太	さとう けんた	男	32	A	東京都千代田区	TRUE
田中 美咲	たなか みさき	女	28	B	大阪府大阪市	FALSE
鈴木 大輔	すずき だいすけ	男	45	O	愛知県名古屋市	TRUE
高橋 由美	たかはし ゆみ	女	25	AB	福岡県福岡市	FALSE
伊藤 誠	いとう まこと	男	39	A	北海道札幌市	TRUE
渡辺 さおり	わたなべ さおり	女	31	B	神奈川県横浜市	TRUE
山本 拓也	やまもと たくや	男	27	O	京都府京都市	FALSE
中村 莉子	なかむら りこ	女	42	AB	埼玉県さいたま市	TRUE
小林 健吾	こばやし けんご	男	36	A	千葉県千葉市	TRUE
加藤 あや	かとう あや	女	29	B	兵庫県神戸市	FALSE
吉田 翔太	よしだ しょうた	男	34	O	広島県広島市	TRUE
山田 奈々	やまだ なな	女	26	AB	宮城県仙台市	FALSE
木村 悠斗	きむら ゆうと	男	48	A	東京都新宿区	TRUE
林 美穂	はやし みほ	女	33	B	大阪府堺市	TRUE
斎藤 健太	さいとう けんた	男	24	O	愛知県豊田市	FALSE
松本 由紀	まつもと ゆき	女	40	AB	福岡県北九州市	TRUE
井上 大輝	いのうえ だいき	男	37	A	北海道旭川市	TRUE
河野 さゆり	こうの さゆり	女	30	B	神奈川県川崎市	FALSE
森下 亮太	もりした りょうた	男	23	O	京都府宇治市	FALSE
石井 舞	いしい まい	女	43	AB	埼玉県川越市	TRUE
原田 拓郎	はらだ たくろう	男	38	A	千葉県船橋市	TRUE
坂本 理沙	さかもと りさ	女	27	B	兵庫県姫路市	FALSE
西村 健二	にしむら けんじ	男	35	O	広島県呉市	TRUE
中川 愛	なかがわ あい	女	29	AB	宮城県石巻市	FALSE
藤田 勇太	ふじた ゆうた	男	46	A	東京都世田谷区	TRUE
遠藤 真紀	えんどう まき	女	32	B	大阪府東大阪市	TRUE
村上 グエン	むらかみ ぐえん	男	26	O	愛知県岡崎市	FALSE
大野 晴香	おおの はるか	女	41	AB	福岡県久留米市	TRUE
金子 拓海	かねこ たくみ	男	39	A	北海道函館市	TRUE
三浦 由佳	みうら ゆか	女	31	B	神奈川県相模原市	TRUE
古川 翔	ふるかわ しょう	男	25	O	京都府舞鶴市	FALSE
高木 菜摘	たかぎ なつみ	女	44	AB	埼玉県所沢市	TRUE
青木 亮	あおき りょう	男	37	A	千葉県松戸市	TRUE
杉山 美香	すぎやま みか	女	30	B	兵庫県尼崎市	FALSE
寺田 健太	てらだ けんた	男	24	O	広島県福山市	FALSE
松浦 陽子	まつうら ようこ	女	42	AB	宮城県気仙沼市	TRUE
野口 翔太	のぐち しょうた	男	47	A	東京都杉並区	TRUE
川崎 シェーン	かわさき しぇーん	女	33	B	大阪府枚方市	TRUE
福島 大地	ふくしま だいち	男	27	O	愛知県一宮市	FALSE
石川 梓	いしかわ あずさ	女	40	AB	福岡県大牟田市	TRUE
岡本 健吾	おかもと けんご	男	36	A	北海道小樽市	TRUE
西田 恵	にしだ めぐみ	女	29	B	神奈川県平塚市	FALSE
島田 マイケル	しまだ まいける	男	34	O	京都府長岡京市	TRUE
谷口 遥	たにぐち はるか	女	26	AB	埼玉県春日部市	FALSE
堀内 雄太	ほりうち ゆうた	男	48	A	千葉県柏市	TRUE
池田 詩織	いけだ しおり	女	35	B	兵庫県西宮市	TRUE
金沢 健太	かなざわ けんた	男	28	O	広島県尾道市	FALSE
橋本 美咲	はしもと みさき	女	43	AB	宮城県白石市	TRUE
荒木 慎吾	あらき しんご	男	23	A	東京都練馬区	FALSE
稲垣 彩	いながき あや	女	38	B	大阪府吹田市	TRUE

👆こちらを A1セルに貼って テーブル名を sampleとしてください。



Q4. 元データと同じ並びの複数列に対する一致条件を数式で生成したい

元データの1列目から6列目まで 同じ並び順で条件キーワードをI2:N2 に入れて、そのキーワードをそれぞれの列が「含む」データだけを抽出したい場合の式を考えましょう。

上の例でいえば、

氏名(1列目)が 田 を含む
and
性別(3列目)が 女 を含む
and
住所 が 大阪 を含む

でデータを抽出したいってことです。

I2:N2 にはキーワードを入れない空白セルもあるので、その点を考慮する必要があります。

考えてみましょう!








↓↓
回答はここから。

↓↓





A4. 元データと同じ並びの複数列に対する一致条件を数式で生成する

回答です。

=QUERY(sample[#ALL],"where "&ARRAYFORMULA(
JOIN(" and ","Col"&SEQUENCE(1,6)&" contains '"&I2:N2&"'")))

こんな式が考えられます。(あくまでも一例です)

解説していきましょう。


まず「含む」条件なので、今回は一番簡単な contains を使います。

contains '' は全てのデータにマッチするので、キーワードが空白のケースはこの時点で解決します。

で、愚直に書くと

=QUERY(sample[#ALL],
"where Col1 contains '"&I2&
"' and Col2 contains '"&J2&
"' and Col3 contains '"&K2&
"' and Col4 contains '"&L2&
"' and Col5 contains '"&M2&
"' and Col6 contains '"&N2&
"'")

こんな式になるんですが、この QUERY式の 第2引数の文字列を数式で生成しているのが

"where "&ARRAYFORMULA(JOIN(" and ","Col"&
SEQUENCE(1,6)&" contains '"&I2:N2&"'"))

この部分です。

まず1列目から6列目までの条件文を作るのに Col1,Col2… という文字が必要なので SEQUENCE関数を使って 1~6の連番を生成します。

この時、条件を記載する I2:N2 と同じ横並びとしておきたいので

SEQUENCE(1,6)

とします。これに Col を付けたいので &で連結するのですが、配列処理となる為 ARRAYFORMULAが必要となります。

ARRAYFORMULA("Col"&SEQUENCE(1,6))

後に contains ' も付けていきましょう。

これに I2:N2 と お尻の 'シングルクォートをさらに連結すれば

列毎の条件記述テキストが生成できました。

あとはこれを 間に and を挟んで連結すれば OKですね。

ここはTEXTJOINでもいいんですが、対象が1次元配列で 空白の考慮が必要ないので、より短い JOIN関数を使いましょう。

ここで  " and " 👈このように  andの前後にスペースを入れるのを忘れずに!

=QUERY(sample[#ALL],"where "&ARRAYFORMULA(
JOIN(" and ","Col"&SEQUENCE(1,6)&" contains '"&I2:N2&"'")))

スッキリ記述できましたね。



元データと並びが違う & 複数列に対する一致条件の場合

=QUERY(sample[#ALL],"where "&ARRAYFORMULA(
JOIN(" and ","Col"&XMATCH(K1:N1,sample[#HEADERS])&
" like '"&IF(K2:N2="","%",K2:N2)&"'")))

もし、条件部分が元データと同じ並びではない場合は SEQUENCE関数が使えないので、条件側の見出しを元データと同じ見出し名を使って XMATCH関数(またはMATCH関数) で引き当てて、列番号を取得しましょう。

XMATCH(K1:N1,sample[#HEADERS])

条件が「一致」の場合でも =(イコール)ではなく、文字列比較演算子を使った方が。列の型を意識する必要がないので便利です。

matches でもいいんですが、今回は より簡単な like を使った回答としています。

" like '"&IF(K2:N2="","%",K2:N2)&"'")

「一致」の場合は条件セルが空白時を考慮する必要があるので、このようにIFで 空白時は % を返し 全ての行にマッチする式としています。


複数列(順不同)を対象とする 「一致」を条件とした 記述もスッキリ記述できましたね。

式による生成は 必要なスペースが漏れたり ミスしがちなんで、一度生成したクエリ文の文字列を出力して目視確認することをお勧めします。



いよいよ QUERY関数 での日付、日時、時刻の取り扱いへ

全体概要に select句 2回、where句 4回 で、ここまで 10回にわたって QUERY関数を徹底解析してきました。

サンプルデータの文字数もカウントされてますが、1回あたり1万文字以上が10回なんで 10万文字以上書いて、ようやく where句まで終わったわけですw

次の句である gruoup by に入る前に、基本の select句、where句が終わったタイミングなんで、先にQUERY関数における「日付、日時、時刻」の扱いに ついて書いておきたいと思います。

ただQUERY関数が続いたので、2,3回別のネタを間に挟んでから QUERY関数シリーズを再開します。

というわけで、次回はQUERY関数以外の別のネタを予定。


いいなと思ったら応援しよう!

mir チップ大歓迎です。やる気がアップしますw