ある日の業務は、sqlite3で取り込んだアンケート結果をシステム向けの横持ち形式に変換する作業でした。内容は「好きなミュージシャン(複数回答可)」を縦に並べたデータ。システムは1ユーザーごとに列が並んだ横持ちを要求していて、最初はイメージがつかめず、本当に頭から煙が出るかと思いました。
縦持ちと横持ち、初心者の私でもわかるイメージ
簡単に言うと:
- 縦持ち:1回答ごとに行がある(user_id, musician のような形)。複数回答は複数行で表現。
- 横持ち:1ユーザーにつき1行、各ミュージシャンを列で持つ(A列: ミュージシャンAの有無、B列: ミュージシャンBの有無…)。
頭でわかると単純ですが、実際のSQLを書くとなると別物です。ここで軽くテンションが下がりました。
迷宮検索とインディ・ジョーンズ気分の発見
ネット検索という名の秘宝探しで、「SQL 縦持ち 横持ち」「PIVOT sqlite3」あたりを巡る旅に出ました。いろいろ読んでいるうちに、sqliteの世界では GROUP BY
と CASE WHEN
を組み合わせて疑似的にピボットする方法が使われていることを発見しました。発見した瞬間は、インディ・ジョーンズが宝箱を見つけたような気分でした。
実際に使ったSQL(シンプルな例)
よくあるパターンの簡単な例を載せます。アンケートテーブル名を survey
、カラムが user_id
と musician
とします。
SELECT
user_id,
MAX(CASE WHEN musician = 'A' THEN 1 ELSE 0 END) AS musician_A,
MAX(CASE WHEN musician = 'B' THEN 1 ELSE 0 END) AS musician_B,
MAX(CASE WHEN musician = 'C' THEN 1 ELSE 0 END) AS musician_C
FROM survey
GROUP BY user_id;
各ミュージシャンごとに CASE WHEN
で該当するかを 1/0 にし、MAX
(あるいは SUM
)でユーザー単位に集約する点です。
Python(sqlite3)からの実行例とPandasで確認
私はPythonを使ってsqliteに接続し、上のSQLを実行してPandasで確認しました。実務ではそのままCSV出力したり、さらに整形したりします。サンプルコードはこんな感じです。
import sqlite3
import pandas as pd
conn = sqlite3.connect('survey.db')
sql = """
SELECT
user_id,
MAX(CASE WHEN musician = 'A' THEN 1 ELSE 0 END) AS musician_A,
MAX(CASE WHEN musician = 'B' THEN 1 ELSE 0 END) AS musician_B,
MAX(CASE WHEN musician = 'C' THEN 1 ELSE 0 END) AS musician_C
FROM survey
GROUP BY user_id;
"""
df = pd.read_sql_query(sql, conn)
print(df.head())
conn.close()
この瞬間、画面に横持ちされたDataFrameが現れたときは、思わず小さくガッツポーズをしました。小さなものでしたが達成感は確かにありました。
私がハマったところ(反省と笑い話)
- CASE WHENで列を固定するため、ミュージシャンの候補が増えるとSQLが長くなる問題。動的に列を作るならPython側で処理する選択肢も必要。
- GROUP BYの集約でNULLや空文字をどう扱うかで一度データが吹き飛びかけた(バックアップ大事)。
実務で役立つちょっとしたコツ
- 候補リストを確定する:まずミュージシャン候補を把握してからCASE WHEN列を作ると安心です。
- まずは少量で試す:LIMITやWHEREで対象を絞って挙動を確認しましょう。
- Pythonで動的にやる選択肢:候補が可変ならSQLで固定列を作るより、Pythonで縦持ち→横持ち(pivot_table/crosstab)する方が楽な場合があります。
- バックアップを取る:必ず元データを残しておくこと。私のように慌てて余計な処理をする前に保存。
まとめ:Python,SQL初心者でもできること
今回はsqlite3で取り込んだ縦持ちのアンケートデータを、GROUP BY+CASE WHENで横持ちに変換してシステム要件に合わせました。最初はSQLの構文にイメージがつかめず苦戦しましたが、検索と試行錯誤で解決できました。Pythonを使えば実行→確認→保存の流れもスムーズで、初心者にも扱いやすいです。