見出し画像

Googleスプレッドシート QUERY関数 超応用例 17(並び替えはorder byで)

Googleスプレッドシートの最強集計関数 QUERY関数シリーズを再開します。今回は第17回です。

👇これまでのQUERY関数シリーズを全て無料マガジンにまとめています。QUERY関数に ダイブしたい人は必読です!

前回まではQUERY関数シリーズをお休みして、少し違うネタを書いていました。

前回のnote【GAS不要】Googleスプレドシート 一番上のセルが常に入力BOXとなるToDoリストを作ろう 

👆Googleスプレッドシートのテクニックてんこ盛りです!(スキ💛は伸びてませんがw)




並び替えをする為の句 order by で出来ること

今回はクエリ文の 第5の句  order by句 を学んでいきましょう。

$$
\begin{array}{lll}
\text{No}&\text{句}&\text{使用量}\\ \hline
\text{1}&\text{select}&\text{出力する列を指定 (類似関数 CHOOSECOLS)}\\ \hline
\text{\text2}&\text{where}&\text{条件でデータをフィルタ (類似関数 FILTER)}\\ \hline
\text{3}&\text{group by}&\text{行方向(縦)にグループ化(類似関数 UNIQUE)}\\ \hline
\text{4}&\text{pivot}&\text{列方向(横)にグループ化(類似関数 UNIQUE)}\\ \hline
\textbf{5}&\textbf{order by}&\textbf{データを並び替え(類似関数 SORT)}\\ \hline
\text{6}&\text{skipping}&\text{〇行おきにデータを出力する}\\ \hline
\text{7}&\text{limit}&\text{〇行目までデータを出力}\\ \hline
\text{8}&\text{offset}&\text{〇行目からデータを出力}\\ \hline
\text{9}&\text{label}&\text{列のラベル名を変更する}\\ \hline
\text{10}&\text{format}&\text{特定の列の値を書式設定}\\ \hline
\text{11}&\text{options}&\text{追加オプションを設定。(使わない)}\\ \hline
\end{array}
$$

前回までの4つの句 select, where, group by, pivot はメイン級の句で、ここからの句は調味料というかサポート的な役割の句です。

order by 以降の句は単体では超応用例があまり無いので、少しペースアップしていきます。



order by は並び替えの為の句 SORT関数的な役割

https://developers.google.com/chart/interactive/docs/querylanguage?sjid=17223248138230870409-NC#order-by

order by句は 指定した列の値をキーとして QUERY関数の出力を並び替えする為の句です。

シート関数でいうと SORT関数ってことですね。

実際にサンプルデータで order by を試しながら学習することをお勧めします。以下を👇 A1:D11 に貼ってご利用ください。

日付	営業担当	商品	売上金額
2025/07/30	山田	A	¥1,500,000
2025/10/15	田中	B	¥2,200,000
2025/03/30	佐藤	C	¥800,000
2024/07/05	山田	B	¥3,000,000
2024/04/03	田中	A	¥1,200,000
2024/12/27	佐藤	B	¥1,800,000
2024/01/05	山田	C	¥700,000
2025/06/10	田中	A	¥2,500,000
2024/12/12	佐藤	B	¥900,000
2025/04/20	山田	A	¥1,600,000



order by句 記述の基本

order by句の記述は、並び替えのキーとする列を第1引数のデータから指定し、そして昇順・降順を指定します。

たとえば1列目をキーに昇順(小 → 大)とする場合は

=QUERY(A1:D11,"order by Col1 asc")


3列目をキーとして降順で並び替えるなら

=QUERY(A1:D11,"order by Col3 desc")

まとめると

order by 指定列 asc   ・・・ 指定列をキーに 昇順で並び替え
order by 指定列 desc ・・・ 指定列をキーに 降順で並び替え

列と asc(desc)の間に半角スペースを入れる

このように記述します。

また上記の式の通り、QUERY関数は select句やwhere句無しで order by句だけを並び替えの為に使うことも出来ます。



oredr byの並び替えルール (型別)

order byの並び替えルールを型別に検証してみました。

基本は > や < といった比較演算子の 大小比較と一緒で、数値だけではなく日付・日時・時刻、ブール値、文字列も並べ替えが可能です。

■数値の昇順
(小さい数値) ➡ (大きい数値)

■日付・日時・時刻の昇順
 前の(早い)日付・日時・時刻 ➡ 後の(遅い)日付・日時・時刻

■ブール値の昇順
 FALSE ➡ TRUE

■文字列の昇順
 A ➡ Z (大文字・小文字の区別なし)

文字列(テキスト型)の並び替えにおいて、日本語は少し特殊な扱いです。これは後で詳しく書きます。

order by で指定した列が同じ値の行があった場合は、基本的には元データの並びが保持されます。

また、並び替えルールの重要なポイントで、上記の型に該当しない 空白(Null)は order byの並び替えではもっとも小さい値(昇順で必ず先頭にくる)という扱いとなっています。

これは後で詳しく触れます。



order by は select と組み合わせて 出力しない列でも並び替えできる

order byで並び替えのキーに指定する列は、必ず第1引数のデータ(範囲)に存在する必要がありますが、select句と組み合わせることで

3列目をキーに並び替えしたいけど、3列目は出力はしたくない

といったことが可能です。

=QUERY(表4a[#ALL],"select Col1,Col2,Col4 order by Col3 asc")

Col3をselect句で指定せず、order by句だけで使用すればOK。

ただしこれには注意点があります。後ほど触れます。



order by句 は where句と組み合わせて空白を除外して並び替える必要がある

上の「並び替えルール」でも触れましたが、空白(Null)はorder by句の並び替えでは最も小さい値という扱いです。

その為、第1引数のデータが テーブルや空白セルを含まない範囲であれば問題ありませんが、A:D のような列全体を対象として order by で昇順並び替えをすると

=QUERY(A:D,"order by Col4 asc")

このように見出しのあとに空白行がきて、その下にデータが昇順で並ぶことになります。

上は検証用に全体を20行としているので、データが下に来ているのがわかりますが、1000行以上あるシートだと「QUERY関数でデータが消えた」と勘違いする人も。

QAサイトでたまに見かける事例です。

これを回避する為には where句 を組み合わせて、空白行を除去した上で並び替えをする必要があります。

=QUERY(A:D,"where Col4 is not null order by Col4 asc")

where Col4 is not null を加えたことで、空白行を除去して正しく昇順に並び替えが出来ました。

where句で空白データを除外する

なお、何度もお伝えしていますがQUERY関数は句の並び順が決まっています。必ずselect句やwhere句は order by 句の前に記述しましょう。



order by句は group byと組み合わせて集計結果で並び替えが出来る【ミニお題】

order by 句のキー列は 第1引数のデータ(範囲)から指定する必要があると書きましたが、例外的に group byと組み合わせた集計の場合は、集計結果をキー列として並び替えをすることが可能です。

👆上は 2列目の営業担当でグループ化して4列目の売上金額の「合計」を集計したものですが、order by句で 売上金額の合計で降順(大きいものが上)に並び替えをしています。

QUERY関数の基本処理の一つですが、これをミニお題として実際に式を作ってみましょう!

元データをテーブル化するかどうかは自由です。group by句のおさらいにもなります。考えてみましょう!





↓↓
回答はここから。

↓↓


【ミニお題 回答】

回答です。

=QUERY(表4c[#ALL],"select Col2,sum(Col4) group by Col2 order by sum(Col4) desc")

=QUERY(A:D,"select Col2,sum(Col4) where Col1 is not null group by Col2 order by sum(Col4) desc")

第1引数の範囲が列指定の場合は空白除去も入れる

出来ましたでしょうか?

order by sum(Col4) desc

と selectでも指定している sum(Col4) をキーとしてあげればよいです。先ほども書きましたが、句の並び順に注意。

この 集計した結果の数値で降順並び替えは、QUERY関数では出番の多い記述です。さくっと書けると便利です。


また、

order by で 集計結果(集計列)を指定して並び替えをする場合は、必ず selectでその集計列を出力する必要があります。

👆上のケースは、出力はグループ化した2列目と2列目の個数 count(Col2) をselectしているのに、selectで指定していない sum(Col4)で並び替えをしようとしてエラーメッセージが出ています。

COL_IN_ORDER_MUST_BE_IN_SELECT: SUM(`Col4`)

集計結果で並び替えをしたいけど出力したくない場合は、一工夫必要ってことです。

また並び替えのキーとして指定する列は集計関数以外にも スカラー関数や算術演算子の利用が可能です。

これらは最後に超応用例で取り上げます。



pivot句の集計(横方向)は order byでは並び替えできない

=QUERY(表4c[#ALL],"select Col2,sum(Col4) group by Col2 pivot Col3")

order byによる並び替えは pivot句を使った ピボット集計とは相性が悪いです。

たとえば 👆のような集計表を order by で並び替える場合

=QUERY(表4c[#ALL],"select Col2,sum(Col4) group by Col2 pivot Col3 order by Col2 desc")

このようにgroup by 句でグループ化した列を指定することは可能です。

しかし、そもそもQUERY関数の集計には合計列がないので、

pivot句を使った集計では、集計列を指定した並び替えは出来ません

また、pivot で指定している Col3(横並びの A,B,C)を逆順にしようとしても、

このようにエラーとなります。pivot句で指定した列(見出しとして横並びに表示)は、order byで並び替えが出来ないってことです。

ただ回避策はあるので、これも最後に超応用例でチャレンジしてみましょう。



並び替えのキー列を複数指定できる

ここまでは並び替えのキー列を1つ指定するケースを扱ってきましたが、order by句は複数の列を指定した並び替えが可能です。

order by キー列1 asc(またはdesc) , キー列2  asc(またはdesc) , ・・・ 

このように order by に続けて カンマ区切り

列指定、半角スペース asc(またはdesc)

を繰り返し記述することができます。

この時、並び替えの優先度は記述順となります。

👆たとえば 上のケースでは

=QUERY(表5[#ALL],"order by Col2 asc,Col3 desc")

Col2で昇順で並べ替えた上で、さらにCol3で降順で並べ替え としています。

つまり Col2が優先順位1、Col3が優先順位2 となります。

順番を変えて

=QUERY(表5[#ALL],"order by Col3 desc,Col2 asc")

このようにした場合は、今度は 先にCol3を降順で並び替えた上で、その中でCol2をキーに昇順で並び替え

このようになります。

あまり使う機会はありませんが、カンマ区切りで複数列を指定して並べ替えが出来ことは頭の片隅にでも入れておくと良いでしょう。



order by の asc(昇順指定)は省略できる

order by の asc は省略することが可能です。

=QUERY(表5[#ALL],"order by Col3")

逆に言えば order by 列 で記述が終わっていたら、昇順並べ替えであるってことです。

これは上で書いた複数列指定と組み合わせることも可能で

=QUERY(表5[#ALL],"order by Col3 asc,Col2 asc")
 ▼
=QUERY(表5[#ALL],"order by Col3,Col2")

このように短縮記述ができます。


order by句の使い方、出来ること(仕様)は理解できたでしょうか?



SORT関数と QUERY関数の order by 並べ替え比較

続いて 並べ替え専用関数であるSORT関数と比較してみましょう。

もちろんorder byは QUERY関数で使える句の一つですから、他の句と組み合わせることでQUERY関数だけで 列・行の絞り込み や グループ集計と合わせて並べ替えができるのが魅力ですが、「並べ替え」だけを比較した場合でも幾つか違う点があります。



order byは 見出し行を固定して(除外して)データ部分だけを並べ替えできる【メリット】

=QUERY(表6[#ALL],"order by Col4 desc")

QUERY関数のorder byで並べ替えをする一番のメリットはコレでしょう。

見出し行を含めまるっとデータを渡した時に、1行目の見出し行を除外(見出しとして固定)した上で、データ部分だけを並べ替えができます。

SORT関数は見出しも含めて並べ替えをしてしまうので、同様のことを実現する場合は 見出しを別で用意するか、一工夫必要となります。

Googleスプレッドシートの SORT関数で 見出し行を含めて対応する

なおQUERY関数の場合は 見出し無しという指定も出来るので、どちらにも対応できるという点も魅力です。



order byは 空白(Null)も含めて並べ替えをする【デメリット】

SORT関数では 空白は並べ替えの対象外扱いとなり、昇順・降順どちらで並べ替えた場合でも、常に空白は 一番下になります。

また、空文字は空白とは明確に区分され、空文字は文字列の中ではもっとも小さい(ただし数値よりは大きい)という扱いになります。

空白と空文字の SORT関数での扱いの違い

これに対して上でも書きましたが、QUERY関数は空白(Null)も並べ替えの対象となります。

QUERY関数においては空文字という考えはないので、空白と空文字は同じものとして扱われ、order byにおいては もっとも小さい値と見なされます。

つまり、空白は 昇順だと一番上に、降順だと一番下にきます

とくに昇順の際は where句での空白除去が必須となるので注意です。



1つの列に型が混在している場合は注意

今回のケースではもう1点注意すべきポイントがあります。

それは大多数の文字列に混じって数値型が同じ列に混在している点です。

SORT関数であれば型が混在していても 数値 < 文字列 として並び替えをしてくれますが、QUERY関数の場合はそうはいきません。

これは order byというよりは QUERY関数の仕様ですが、1つの列に複数の型が混在できない仕様となっています。

QUERY関数で型と合わない小数派データの末路

今回の場合はテキスト型が大多数である為、数値である 8,30 は文字列の数字として扱われています。

その為、本来は 8の方が30より小さいのに 文字列として先頭から見た時に 8と3を比べて 3の方が小さいということで 昇順では 30 ➡8 と逆の並びになっているわけです。

1つの列に違う型が混在するデータはQUERY関数で扱うのは避けた方がよいです。



order byは 半角・全角、ひらがな・カタカナ、濁音・半濁音を 厳密に区別して並べ替える【メリット】

はんだごて
カアちゃん
ABC
ぱいなっぷる
バキどう
カアサン
かぁさん
BCD
パープルヘイズ
かいんずほーむ
ばきらへん
かあさん
ガーゴイル
カーセンサー
CDA
かあせんさあ
きゅーと
きゆうと

👆こんなデータがあった時に、SORT関数で並び替えると

このように非常に違和感のある結果となります。

これはGoogleスプレッドシートのSORT関数の並び替えが、

半角・全角、ひらがな・カタカナ、濁音や半濁音や小さいかな、これらを区別せずに並び替えする為です。(※区別している処理もあります)

このGoogleスプレッドシートの日本語、全角文字の曖昧な仕様は、過去に何度か一致という観点で取り上げています。


これに対してQUERY関数の order by は

これらを明確に区別した並び替えとなっています。

同じ並び替えでもだいぶ違いますね。

半角英字 < ひらがな < カタカナ < 全角英字 < 半角カナ

このようになっていて、さらにひらがなやカタカナ内では

ぁ(小さいかな) < は < ば(濁音) < ぱ(半濁音) < ー(伸ばし棒)

となっています。

これはユニコード値 が基準になっているようです。

細かい点を気にする必要はありませんが、

SORTとQUERY関数の order byでは 日本語の並び順に違いがあって、ひらがなやカタカナ、「は」「ば」「ぱ」を区別して並び替えしたい!という場合は QUERY関数の order byが使える!ってことです。



order by は漢字の並び替えには使えない【デメリット】

そもそも漢字をキーに並べ替えをすべきではないんですが、SORT関数だと割と感覚的に音読みベースで並べ替えをしてくれるので、そこまで大きな違和感がありません。

しかし、QUERY関数の order byは漢字をキーにすると「なんで?」という並び順になります。

普通の感覚だと先頭にくるはずの「阿部」が一番下にきてますね。

これも並べ替えの基準として使われているのは ユニコード値だと思われます。

漢字でをキーとする並び替えは避け フリガナ列を用意して、それをキーに並び替えをしましょう。


SORT関数との仕様の違い、使い分けのポイントも理解できたでしょうか?



QUERY関数 order by句 超応用例

最後に order by句を使った超応用例のお題3問にチャレンジしましょう!



Q1. 値の登場する順番を維持したままグループ集計したい(SORT関数を使わずに)

最初のお題です。order by句を応用して 表を2列目(担当営業)でグループ化して4列目(売上)の合計をグループ集計する際、営業担当を元の表の登場順を維持したい場合、どのような式を組めばよいでしょうか?

ただしSORT関数は使わず group byで対応する を条件とします。

考えてみましょう!








↓↓
回答はここから。

↓↓





A1. 値の登場する順番を維持したままグループ集計する(SORT関数を使わずに)

回答です。

=QUERY(
  QUERY(
    {表Q1[#ALL],ARRAYFORMULA(ROW(表Q1[#ALL]))},
    "select Col2,sum(Col4),min(Col5) group by Col2 order by min(Col5)"
  ),"select Col1,Col2"
)

QUERY関数を2段階で利用していますが、ポイントはそこではなく

最初のQUERY関数の第1引数(データ)を

{表Q1[#ALL],ARRAYFORMULA(ROW(表Q1[#ALL]))}

として、元のテーブルの右にバーチャルな行番号を入れた列を連結して

この5列目(行番号)の最小値を 集計して、それをキー列として降順並び替えを行います。

order by min(Col5)
※ asc を省略しています

これによって Col2をグループ化しても登場順を維持できます。

ただしorder by句の仕様上、この並べ替えのキーとして使う min(Col5) を select句で指定して出力する必要がある為、これが邪魔になります。

ExcelのDROP関数があれば さくっと処理出来るんですが、残念ながらGoogleスプレッドシートには無いので再度QUERY関数で select Col1,Col2として3列目を除外しています。

集計結果で並び替えをしたいけど出力したくない場合は、このように一度出力してからQUERY関数のネストでselect句で除外する方法があります。

※QUERY関数の回なんでQUERY関数を2回使ってますが、3列目を除外する処理は CHOOSECOLS関数を使ってもよいです。



Q2. QUERY関数でピボット集計の見出しの横並びを降順(左が大きい)に変えたい

こちらも group by句の仕様を解説する中で、出来ないと書いた処理です。

pivot句で指定した列は 通常はグループ化(ユニーク処理)され、左から昇順で横並びになります。

これを逆順(左から降順)としたい場合、どのような式を書けばよいでしょうか?

考えてみましょう!








↓↓
回答はここから。

↓↓





A2. QUERY関数でピボット集計の見出しの横並びを降順(左が大きい)に変える

回答です。

=TRANSPOSE(
  QUERY(
    TRANSPOSE(
      QUERY(表Q2[#ALL],"select Col2,sum(Col4) group by Col2 pivot Col3")
    ),
    "order by Col1 desc"
  )
)

これは割と簡単でしたかね。

SORT関数にしろ order by にしろ、Googleスプレッドシートには横方向の並べ替えが出来る関数はありません

だからTRANSPOSE関数で向きを変えて、縦方向で並べ替え処理をしてから再びTRANSPOSEで戻すという手順が必要になります。

向きを変えてからの並び替えは、見出しを固定したデータ部分だけの並び替えが必要なので、ここはSORTりもQUERY関数のorder by句が適しています。


一応【別解】として、自動で左から昇順に並んでいるので、一番左側の見出し列以外を逆順にselect句で指定するという方法もあるので紹介しておきます。

=LET(
  x,QUERY(表Q2[#ALL],"select Col2,sum(Col4) group by Col2 pivot Col3"),
  QUERY(x,"select Col"&JOIN(",Col",UNIQUE({1;SORT(SEQUENCE(COLUMNS(x)),1,0)})))
)



Q3. QUERY関数の日付の集計を年度(4月はじまり)としたい

最後のお題です。

QUERY関数で年、月で売上金額の合計を ピボット集計をする際に「年度」(4月はじまり)としたい場合はどうすればよいでしょうか?

ポイントは2つ。

翌年 3月末までは 前の年度となるので、データ内の 2024/01/05は、2023年度となります。このように年を年度とみなすように調整する必要がある

もう1つが月の並びを4月スタートで最後を3月とする並びにする必要がある。

これらをクリアする必要があります。

なおこのお題はQUERY関数は1回だけで処理出来ます。考えてみましょう!









↓↓
回答はここから。

↓↓





A3. QUERY関数の日付の集計を年度(4月はじまり)とする

回答です。

=QUERY(
  {表Q3[#ALL],ARRAYFORMULA(EDATE(表Q3[[#ALL],[日付]],-3))},
  "select month(Col1)+1,sum(Col4) group by month(Col1)+1
   pivot year(Col5) order by (month(Col1)+1+8)%12"
)

まず年度に関しては作業列 

ARRAYFORMULA(EDATE(表Q3[[#ALL],[日付]],-3))

で1列目の3か月前の日付を生成。これを元データの右に連結して5列目とした上で、 year(Col5) とするのが簡単です。

EDATE関数は日付を第2引数で指定した数値分ずらした日付を返す関数です。マイナス指定で〇ヶ月前の同じ日を返します。

これによって 2024年1月-3か月で 2023年10月 となるので year(Col5)は 2023と 年度の数値を返します。 

実は 月の方も month(Col5) をselect と group byで指定して

order by month(Col5) とすれば、month(Col1)+1 は 4月-3月 の並び順になるんですが、これだと1列目を削除する為にもう1回QUERY関数やCHOOSECOLS関数の処理が必要となります。

とくにピボット集計は、列数が可変となるので式が少々面倒です。

ここは month(Col1)+1 を加工した 配列を order byで利用することで、4月はじまりの並び順としましょう。

その式が 

order by (month(Col1)+1+8)%12

この部分です。

0~11月となっている12個の 月の数字から 3(4月)を先頭に(一番小さく)するには、3 +1(4月) が12で割ったときに余りが0となるようすればOK。

%は シート関数の MOD と同じ、割った時の余りを返すQUERY関数の隠れ演算子です。

算術演算子(実は % 剰余も使える)

というわけで month(Col1)+1にさらに +8 して 12で割った余りの配列をキーとして 昇順で並び替えれば良いってことですね。

order by (month(Col1)+1+8)%12

👆これ普通に考えると  (month(Col1)+1)+8) の部分は month(Col1) + 9 でいいんじゃないの?と思うかもしれませんが、

+9にまとめると エラーとなってしまいます。

これは group by によるグループ集計を order by で並び替える際は、

select句で指定している列(またはその列を加工したもの)

だけが指定可能となっている為です。

+1+8 を計算して +9 としてしまうと、select句で指定している 

month(Col1) + 1 を加工したと見なされません


ここは month(Col1)+1 という形を残したまま、orde by句で

order by ( month(Col1)+1 +8)%12

このように指定する必要があるってことです。難しいですね。。

これで月の並び順を4月スタートとすることが出来ました~。

=QUERY(
  {表Q3[#ALL],ARRAYFORMULA(EDATE(表Q3[[#ALL],[日付]],-3))},
  "select month(Col1)+1,sum(Col4) group by month(Col1)+1
   pivot year(Col5) order by (month(Col1)+1+8)%12"
)


ちなみに作業列を生成せずに、年の方のズレも1~3月の場合は年を-1するという式をQUERY関数内で演算子やスカラー関数を駆使して組むことが出来ます。

=QUERY(
  表Q3[#ALL],
  "select month(Col1)+1,sum(Col4) group by month(Col1)+1
   pivot year(Col1)+
    (15-14)%((month(toDate(Col1))+13-12-
      (month(toDate(dateDiff(Col1,date '19700-01-01')*86400000))
        +11-10)%4)/(6-2)+17-16)+19-20
   order by ((month(Col1)+1)+8)%12"
)

もしくは

=QUERY(
  表Q3[#ALL],
  "select month(Col1)+1,sum(Col4) group by month(Col1)+1
   pivot year(Col1)
    - dateDiff(
      toDate(((7-6)/(dateDiff(
        toDate((month(toDate(Col1))+4-3)*21600000),date '1970-01-01'
      )+10-9))*86400000),date '1970-01-02'
    ) 
   order by ((month(Col1)+1)+8)%12"
)

ただ、同じ記述(数字など)を2回使えないという謎縛りのせいで、かなり式が長くなり複雑化します。。

これに頭を悩ませるよりは、作業列で対応しちゃった方が早いですね。


以上、order byを使った3つの超応用並べ替えでした~。



order by句で並べ替えを自由自在に!

今回はQUERY関数の order by句をディープに学びました。

基本の使い方から、SORT関数との違い、超応用例まで、理解できましたでしょうか?

グループ集計と組みあわせた並べ替えは非常に強力です。活用ください!

次回はQUERY関数のデータ出力を制御するオプション

skipping、offset、limit

の3つの句を一気に取り上げます。


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

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