0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SQLが書けない俺は、SQLを書かない為に“組み立てる言語”を作った

Last updated at Posted at 2025-11-03

諸君、私はSQLが苦手だ

この記事を読めば「SQLは文字列ではなく部品だ」という感覚がインストールされる。
そして、「頭の中では答えが見えているのに、実装が上手くいかない…」というあの苛立ちこそが、まさに「認知摩擦」である。

SQLで何度も胃が痛くなった。

手書きのノートでロジックを整理して、何時間も考えて組んだクエリが
スペースひとつや [] の有無だけで動かない。
原因を突き止めるのにさらに数時間。
やっと動かしても、翌週の仕様変更で全部作り直し。

そしてトドメはパラメータクエリだ。
「これでダイナミックSQLが簡単に書ける!」と期待したのに
Accessではパラメータ化できるのはWhere句だけだと知って絶望した。

条件分岐で、SQLが複雑に変化する機能を実装していた時の話だ。
パラメータークエリは「Where句」しかパラメータ化できない。
だから僕は、命令単位で変数を宣言し、その変数を連結するコードを書いた。
悪いアイデアじゃない。
クエリが1つしかないならな。

1機能の中で複数クエリがあると、変数は雪だるま式に増える。
これが「最適解」でないのは明らかであろう。

.vba
    Dim StrSelect1  as String
    Dim StrFrom1    as String
    Dim StrWhere1   as String
    '.
    '.
    '.
    Dim StrSelect5  as String
    Dim StrFrom5    as String
    Dim StrWhere5   as String

ハードコーディングよりはマシだ。
でも、全然「綺麗」じゃない。
しかも仕様変更のたびに、全部作り直しだ。
その時、心の中で叫んだ。

いっそ “命令句そのもの” が変数なら良いのに。

SQLを書かないアイデアの誕生

こで俺は気付いた。

SQLは“文”じゃない。
部品を組み合わせた「オブジェクト」だ。

だったら、命令句を全部「変数」にすればいい。
後は、好きな順に並び替えるだけで、クエリは自動的に「出来上がる」。
俺は VBA で “命令句を1つの型にまとめる箱”
SqModel」を作った。

クラスモジュールには
SQLの「命令句ごとのプロパティ」、そして「SQLの全文を意味するプロパティ」を定義する

.vba
' SqKernel.cls(抜粋)
'■命令句プロパティー
Private Select_  As String
Private Delete_  As String
Private From_    As String
Private Update_  As String
Private Set_     As String
Private Where_   As String
Private GroupBy_ As String
Private Having_  As String
Private OrderBy_ As String

'■全文(ビルド結果)
Private All_     As String

そして、同じモジュール内にはプロパティ値をSQLの文法通りに並び替える「文法ロジック」を実装する

.vba
'プロパティをSQLの文法に基づいて並び替える文法ロジックの抽象コード
'この「文法ロジック」は対象となるデータベースのSQLの文法に応じて実装を行う。
function MODELING(SqModel):
    out = ""
    for clause in ["SELECT","FROM","WHERE","GROUP BY","HAVING","ORDER BY"]:
        body = model[clause]      # 命令句に相当する文字列(空ならスキップ)
        if body is empty: continue
        if body does not start with clause:
            body = clause + " " + body
        out = out + (" " if out != "" else "") + body
    return out + ";"

SQmodel が無い場合(素朴な実装)→ 地獄

以下は三重クエリを「SqModel」なしで実装した例である
なお、今回はデモンストレーションとして「やさしめ」の更新クエリを生成してみよう。

vba
Dim strSub1 As String, strSub2 As String, strUpd As String

strSub1 = "SELECT 販売担当者ID FROM 販売履歴 WHERE 販売数量 >= 10"

strSub2 = "SELECT 社員名 FROM 社員マスタ WHERE 社員名 IN(" _
        & strSub1 _
        & ")"

strUpd = "UPDATE 社員評価テーブル " _
       & " SET 評価 = 5" _
       & " WHERE 社員名 IN(" _
       & strSub2 _
       & ");"

Debug.Print strUpd

・3つ前のクエリを 2つ前のクエリが参照し、
・それを 1つ前のクエリが参照して…
・カッコ・スペース・セミコロンで死ぬ
3段ネストになるともう “無理ゲー” 。
そして、これはあくまでも「デモンストレーション」
実際はもっと複雑難解である事がデフォだ。

SQmodel の場合 → 3段ネストなのに「3行✕3ブロック」で終わる

vba
' INサブクエリのヘルパ
Private Function InSub(ByVal subSql As String) As String
    If Len(Trim$(subSql)) = 0 Then Err.Raise 5, "InSub", "サブクエリが空です。"
    InSub = " IN (" & subSql & ")"
End Function

' サブ1:一定数以上売った担当者ID
Dim mdSub1 As New SqModel
With mdSub1
    .SELECT_ = "販売担当者ID"
    .FROM_   = "販売履歴"
    .WHERE_  = "販売数量 >= 10"
    .Modeling
End With

' サブ2:社員マスタで対象の社員ID抽出
Dim mdSub2 As New SqModel
With mdSub2
    .SELECT_ = "社員ID"
    .FROM_   = "社員マスタ"
    .WHERE_  = "社員ID" & InSub(mdSub1.All)
    .Modeling
End With

' 主:評価更新
Dim mdUpd As New SqModel
With mdUpd
    .UPDATE_ = "社員評価テーブル"
    .SET_    = "評価 = 5"
    .WHERE_  = "社員ID" & InSub(mdSub2.All)
    .Modeling
    Debug.Print .All
End With

・命令句を書くだけ
・ネストの深さと「コード量」が比例しない
・仕様変更が来ても、命令句だけ直せば終わる

なお、
「短く書ける」=「安全に書ける」ではない。
SqModelは書き手のスキルに関係なく、"文法的に正しいSQL"を生成する仕組みだ。

最後に

要するに僕は

SQLを“書く”のをやめた。
SQLを“組み立てる”ことにした。

その結果、VBAの中に
SQLの internal DSL が生まれてしまった。

諸君、私はSQLが苦手だ。
だから言語を作った。

次回予告
SqModelがなぜ「DSL」なのか?

それは命令句を“文章”ではなく
部品”として取り扱っているからだ。

次回は、たった1つの処理
方言の切り替え」を紹介する。

この一手で ――
SQmodelは Access → SQLServer に化ける。
(SQLを書かずにだ)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?