ExcelのSQL構文
[Microsoft][ODBC Excel Driver]
※個人情報っぽいデータは「疑似個人情報生成」様で生成したダミーです
※いろいろ試した結果、ExcelSQLはデバッグ効率が最悪なので使わない方がいい…そもそも困った時に参照できる公式ドキュメントがない。なんのために実装したのか謎
代替案としてパワークエリか、Accessが使えるならAccessが最強かもしれない(まだ試してない
SELECTの文
基本構文
FROM句は シート名の末尾に「$」マークをつけて[ ] で囲む
あと保存してあるブックのシートじゃないとダメ
(新規ブックで未保存の場合、シートはまだ存在しない扱いとなる)
SELECT * FROM [データ$];
重複削除:DISTINCT
SELECT DISTINCT 都道府県 FROM [データ$];
上位x件:TOP
このSQL文は偶然上にあるレコードを10個取得するだけ
ORDER BYを付け足してソートするとTOP10ランキングを作れる
逆に下からx件を取得したい場合、それ専用のコマンドは無いのでソートを上手く組み合わせてなんとかするしかない
SELECT TOP 10 名称,株価 FROM [Sheet2$]
列の結合
数値はCSTR()を使えば文字列として扱われる
SELECT CSTR(連番)+氏名+CSTR(年齢) AS 列の結合 FROM [Sheet3$]

計算列の作成
()で囲まなくても問題なく動きますが可読性を上げるために囲んでます
SELECT
(年齢+連番) AS 列の足し算,
(年齢-連番) AS 列の引き算,
(年齢*連番) AS 列の掛け算
FROM [Sheet3$]

割り算は0があるとエラーになるので注意(エラーメッセージのパターンが何種類もあり原因の特定が難しい。この例みたいにちゃんと「0で除算した」と教えてくれたら運が良い)
回避方法は次のIIF()で

SELECTで条件分岐
IIF(条件, TRUEの場合, FALSEの場合)
入れ子にできるので、「列1が0より大きい」AND「列2が0より大きい」という条件式を作れる
これで「0で除算しました」を回避できる
SELECT IIF(列1>0,IIF(列2>0,列1/列2,0),0) AS 計算列 FROM [Sheet3$]

Switch(条件1, TRUEの場合, 条件2, TRUEの場合, ….)
SELECT CASEみたいに使える
SELECT 名前,Switch(番号=0,'ゼロ番',番号=1,'イチ番',番号=2,'ニ番',番号=3,'サン番') AS 計算列
FROM [Sheet3$]

SELECTで関数
REPLACE()
SELECT REPLACE(氏名,'宮','山') AS 名前 FROM [Sheet3$]

LEFT()、RIGHT()
+で連結できる
SELECT LEFT(氏名,1)+'山' AS 名前 FROM [Sheet3$]

「年代」列の作成
SELECT 氏名,IIF(年齢>=60,'60代以上',LEFT(年齢,1)+'0代') AS 年代 FROM [Sheet3$]

WHERE句
部分一致検索:LIKE
ワイルドカードは*ではなく%である
前方一致:WHERE 列名 LIKE 'キーワード%’;
中間一致:WHERE 列名 LIKE '%キーワード%’;
後方一致:WHERE 列名 LIKE '%キーワード’;
アンダースコア「_」は「1文字の」ワイルドカードになる
SELECT SC,名称,市場 FROM [データ$] WHERE 名称 LIKE 'ファ%';

IN:配列でOR指定できる神機能
「NOT IN 配列」で除外もできる
SELECT SC,名称,市場 FROM [データ$] WHERE 業種 IN ('建設','非鉄金属','鉱業');
サブクエリも使える(この例はあまり意味ないが一応動作確認)
SELECT SC,名称,市場 FROM [データ$]
WHERE SC IN (SELECT SC FROM [データ$] WHERE 名称 LIKE '%日本%';);

グループ化
構文:GROUP BY「集約キー」
集約キーは列名のどれかを指定 SELECTする列も集約キーと一致しないとだめ
SELECTの部分で「AS 名前」と書けば出力後の列名を指定できる
SELECT 市場,COUNT(*) AS TEST FROM [データ$] GROUP BY 市場;

複数の集約キーでグループ化し、HAVINGでフィルター
SELECT 市場,業種,SUM(出来高) AS 出来高合計 FROM [データ$]
GROUP BY 市場,業種 HAVING 市場='東証一部';

ソート:ORDER BY
基本:ORDER BY 「列名」
降順:ORDER BY 「列名」 DESC
複数:ORDER BY 「列名1」 DESC, 「列名2」 DESC, …
できないこと
FROM句はサブクエリが使えない
一般的なSQLはFROM句でサブクエリを使用できるがExcelは対応してない
「ワークシート作成→SQL実行→ワークシート削除」という処理で一応同じことができる
ExcelのSQLでピボットテーブルは作成できない
マクロの記録→ピボットテーブル作成でコードを調べてなんとかするか、ワークシートに数式を埋めるしかない(意外と後者の方が楽)
JOIN
なぜかJOIN句が無くてもJOINされる
これが

こうなる

ただしシート1とシート2に同じ列名があるとエラーになるので出身地テーブルのIDを「syussinID」にした
SELECT 名前,出身地名 FROM [人$],[出身地$] WHERE 出身地ID=syussinID;
アウターJOINもできた
FROM [シート1$] AS A [シート名2$] AS B ON A.列名=B.列名 みたいな感じ
ChatGPTに聞けばちゃんとした構文教えてくれる
タグ機能の実装方法
1)レコードIDとタグIDで多:多の中間テーブルを作る
2)まずタグ名をJOINしてレコードIDとタグ名のテーブルを作る
3)「SELECT レコードID WHERE タグ名=狙いのタグ」で絞り込む
4)3のレコードIDリストをサブクエリにすればOK
(WHERE レコードID IN (サブクエリ)」で抽出)