スプレッドシートとBQをつなぐときに空行と日付周りの挙動で苦労した話（BQにつなぐスプシは空行を消せ）

# まとめると

GSSとBQをつなぐときは空行に気をつけろ
特にDATE（今回なってないけどDATETIMEもかも）はGSSとBQで持ち方違うかも
データとしてBQにつなぐスプレッドシートには空行を作らないほうがよさそう

# 背景

GASで週次でスクレイピングしてスプレッドシート（以降GSS）に流し込んで、GSSからLookerStudioにデータ読み込んでグラフ表示してるが、変化率を作りたいのにLAG的な関数がLookerStudioにもGSSにもなさそうなのでBQでやることにした。
（技術選定？しらん、慣れてるだけじゃ この規模なら多分タダだし）

で、BQにGSSからテーブル追加したあとの話。

# 起こったこと

テーブル追加だけなら何事もなく終わったので、とりあえず表示してみようとして
```sql
select *
from `idolscouter.spreadsheet.listener`
```
したら、なんかめっちゃ時間かかって3分待たされて、
>Error while reading table: idolscouter.spreadsheet.listener, error message: Row 2178 has only 3 columns, while at least 4 are needed because the index of the rightmost required column is 3. File: {シートのID}

で実行失敗した。

# 調査

## シートの中身

シートの中身は現時点で2178行*4列で大したものではなく、ファイルサイズにしても20KBくらい。
このエラーメッセージは0オリジンな気がするので、（あってれば）データが入ってる次の空行が変、と言ってますねこれ。
データの末尾はこんな感じ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2834707/17d58e20-507a-ae51-a4b2-94380d8660ec.png)

あと、こんなデータサイズでそもそも処理に時間かかるわけがないのだが、これは一つ心当たりあり。
上述の通り、GASで週次実行しているのだが、ちょっと前にLookerStudio見てたらデータが欠損しており、スプシ見ると途中で終わっててなんか行数が足りてない気がする、となったのでえいやで200万行くらいまで増やしてた。

別のもっと簡単な（STRが2個しかない）GSSをBQに繋いだときはうまく出来てたので、何だ？形の違いか？？と思い、スキーマを全部STRにして読み込みなおしてみても変わらず…
NULLABLEにすると、1999999行表示され、2178行目以降はすべてnull。

## （脇道）セル数上限パンパンのシートにはGASで行挿入できないみたい
このシートは200万 * 4なのでまだセル数余裕あるが、別で作ってる200万 * 5のシートへ挿入するために、getLastRow()を使うと、
>TypeError: Cannot read properties of null (reading 'getLastRow')

と怒られてしまった。
データが入ってなくても、用意されているセル数が上限に達しているとこのエラーが起こるみたいなので、結論無駄にセルを作るのはやめましょう。
（厳密に言うと挿入じゃなくて、getLastRawができないだけかもしれんが）

 ~~いやそもそもセルいっぱいになったら挿入できなかったからわざわざ空行大量に作ったのになんだったん…？~~ 

## （本筋に戻って）参考文献

https://qiita.com/Otofuke/items/78dccd3cd7bef5a3faa4

エラーメッセージでググったらこんな記事あり。
どうやら日付周りでなんか変ぽい。
空行周りの挙動も同じだね。

https://stackoverflow.com/questions/71713007/what-does-this-error-mean-required-column-value-for-column-index-8-is-missing

これ見るとnullabeにするなって言ってるけどもうやってるのでダメ。

# 解決方法を考える

STRしかないシートだとこの事象起こらなかったので、日付の持ち方をyyyyMMddのSTRにしてあとでcastする（どうせBQでこねこねしたくてBQ触ってるので）という手をまず思いつき、試してみてうまくいったが200万行読み込んでることには変わらずselect *だけでまあまあ時間食うのでできれば避けたい。

いろいろ試した結果…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2834707/26a4edb6-a84d-8027-2dfa-94669b9c6868.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2834707/3d464c2f-0a59-5d2c-40b6-e0f227d739b0.png)

末尾の空行なくしたらいけました。（何？？？？）

GSS側では、日付列の形式は「自動」ではなく「日付」にし、GASから流し込むデータ形式はyyyy-MM-ddにしてます。
（BQは後者になってますね）

# 結論

BQにつなぐスプレッドシートはピュアにデータとして・CSVとして使うと思うので、仮にあとから更新する場合でも空行を残しておくのはよくなさそう。
特に日付など表示に関わる形式がある場合はなおさら。
GASで挿入するときも行足りなかったら自動で付け足してくれるみたいなので、そっちに任せれば良い。
1ファイルの中で合計1000万セルが上限。MSのエクセルとかと違って行・列削除すると存在がなかったことになる（上記例の場合、E列以降が存在しない）ので、余計な列・シートを削除しておくと上限行数が稼げる。

ちなみにBQとGSS接続すると、BQにはデータ保持せず、fromで読み込むたびに参照しに行くような形になってるぽい。
なのでプレビュー見れないし、シート更新してすぐクエリ叩いても反映されてる。
テーブルにパーティション持たせるとかしないのであれば、BQ側の自動実行等は不要で、シートのみ何かしらの手段で更新すればOK。

# （余談）ちなみにこれ何作ってんの？アイドルのなに？

https://x.com/haaaaazimeeee/status/1778215720641548293

このツイートにインスパイアされて、週次でspotifyのリスナー数・フォロワー数を取るやつを作りました。

https://lookerstudio.google.com/reporting/43a9e37d-846a-4249-afac-2aead9d812f2

こんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2834707/3d60b5e8-0b13-ab72-3b7c-c5f772dbb896.png)

APIからはリスナーが取れず、私の低い技術力では有効数字最大3桁くらいになってますがまあ御愛嬌ということで。
（野良API落ちてたんだけど、有料だったのでやめた）
（HTMLで描画してない？くて俺の技術力では無理だった）
（野良API使うカネくれるかAPI実装して提供してくれるかスクレイピングの仕方教えてくれたら1の位まで実装可能ですので提供お待ちしております:hugging:）

んで、背景にも書いた通り変化率を取りたかったんだけど、LAGがないのでBQでやることにしました、という経緯。
GSSにつなぐところは無事出来たので、あとはBQで書いてつなぎ直すだけ。