Query Language Alternative

SQLの柔軟性はそのままに、
チーム開発のための新しいクエリ言語

データ分析において欠かせない存在であるSQLは、非常に柔軟な表現力を持ち、50年以上にわたり使われ続けています。Qualtは、刻々と変化するデータと現代のチーム開発に対応するため、SQLを言語レベルで再設計します。

Qualtの特長

Key Features of Qualt

Statically-Typed Modular System

クエリを使い捨てにせず、蓄積するチームの財産に

静的解析を備えたモジュールシステムにより、巨大なクエリを再利用可能なパーツへ分割できます。変更の影響を把握しながら、プロジェクトを継続的に発展させられます。

  • 巨大なクエリを分割実装、よく使う部品はチームで共有
  • 型制約を定義して安全にクエリを変更
  • クエリだけでなく、テーブルの定義もセットで管理

-- モジュールを定義

MODULE ranged_orders(

    start_date TIMESTAMP DEFAULT "2026-01-01"

) =>

 

SELECT

    order_id,

    num_of_item

FROM thelook_ecommerce.orders

WHERE shipped_at > start_date;

 

-- モジュール呼び出し

SELECT avg(num_of_item) AS avg_num_of_item

FROM ranged_orders()

Declarative Modeling Layer

クエリそのものがドキュメントとなり、設計意図を伝達

SQLだけでは表現できないメタ情報や注釈を、クエリに直接書き込めます。書き込んだ情報は統合管理され、他の開発者やツールからすばやくアクセスすることが可能です。

  • 型だけでは表現できないデータの制約を定義、違反はユーザーに即座に通知
  • 情報はエクスポート可能。マテリアライズやドキュメント生成を行う外部ツールと連携

-- マテリアライズ方法の指定

@materialize(materialize_type="table")

select

    -- 連番の注文ID

    order_id @unique @reference(target=order_items.id),

    sum(product_retail_price) as total_retail_price,

    sum(cost) as total_cost,

FROM inventory_items AS ii

LEFT JOIN order_items AS oi ON ii.id = oi.inventory_item_id

GROUP BY order_id

Integrated Query Workspace

クエリ開発に必要な情報を統合した開発環境

プロジェクト全体の既存クエリやテーブル情報など、実装に必要な情報をエディタに統合。クエリを記述しながら、コンテキストを失うことなく開発を進められます。

  • カラムの名前やデータの内容を知らなくてもクエリを書きはじめられる(completion, hover等のLSP Methodに対応)
  • コードジャンプや参照元検索で巨大なプロジェクトでも安心
  • クエリの静的解析による素早い応答
Codatum

Declarative Modeling Layer

SQLをアップデートする

使い慣れたSQLの感覚を維持しつつ、その柔軟性を損なうことなく、より明快で一貫性のある構文へ再設計しました。

  • 関数・コンストラクタの構文をシンプル化、パラメータ定義はエディタで確認
  • ASキーワードの有無などの迷いを生む選択肢を除去
  • FROM句から書き始められる SELECT文を追加

-- FROMから書き始められるSELECT文

QUERY FROM thelook_ecommerce.orders

WHERE shipped_at

    BETWEEN "2026-01-01" AND "2026-02-28"

GROUP BY order_id

SELECT

    order_id,

    -- パラメータ構文のシンプル化

    -- 2nd parameter true => ignore nulls

    first_value(num_of_items, true)

開発方針

Development Policy

Qualt をクエリ言語・環境として価値あるものにするため、以下の方針に従って開発を進めています。

高速応答を追求する

ソースコードやデータの解析処理の高速な応答を追求します。なによりもまずクエリを書く環境として快適なものであることを目指します。開発の継続によって変化していくボトルネックに粘り強く向き合います。

クエリだけでなくデータベース情報も統合

データベースのデータ・メタデータに関する機能を明確にスコープに入れます。ユーザーがデータベースとクエリを行き来する手間を減らし、クエリ記述とデータ探索の距離を縮めます。

マルチデータベース対応とそのための言語設計

複数のデータベースに対応するとともに、対応データベースが増えても現実的なコストで開発が継続できるように言語仕様を定めます。Write Once, Run Any Databaseにするのではなく、型名や関数はなるべくバックエンドデータベースのものをそのまま使用し、複雑な方言は構文解析をパスして直接記述できるようにします。

機械処理可能

クエリを分析した結果得られる情報は機械で処理できる形式でも出力できるようにします。外部ツールとの連携だけではなく、LLMから利用されることを考慮してCLIを実装します。

SQL for Team Development

チーム開発のためのSQLへ

生成AIがデータ分析業務を変革する中、SQLはエンジニア、ビジネスユーザー、AIを結ぶ共通言語としての役割を担います。
本プロジェクトは、SQLそのものをアップデートし、現代に適したプロダクションレベルの言語へと進化させます。

Qualtは今後、一部のオープンソース化やCodatumへの組み込みを予定しています。
現在開発中のため、SQLを使う上での課題や、欲しい機能についてぜひご意見をお聞かせください😉

株式会社CODATUMは、SQLを軸とした製品開発を通じて、チームによるデータ活用を実現していきます。

アーキテクチャと実装

Architecture & Implementation

構成

Qualtは、コンパイラを含むコマンドラインツールとLSP Server / Clientで構成されています。

  • コンパイラCLI: ソースコードを静的解析し、生SQLに変換
  • ソースコード形式: exsqlクエリファイル単独、またはQualt型定義ファイル + 生クエリファイルの組み合わせに対応
  • データチェック: 統計データとソースコードを照合し、不整合を検出
  • 分析結果の出力: 外部スケジューラやドキュメントジェネレータが利用可能な形式で出力
  • LSP Server/Client: ユーザーのクエリ記述をサポート、コンパイラと同一の分析エンジンを使用
Qualt開発画面

構文解析

ソースコードを静的に解析することで、クエリを実行せずに各モジュールの定義や状態を把握します。

エラーに強い構文解析

コーディング中は構文が不完全になることがありますが、QualtはLSP対応を前提に、トークン欠けに強い文法定義を採用。トークン欠損は意味解析フェーズでエラーとして検出し、構文解析失敗時も前回成功時の解析結果とコード変更履歴から適切な言語サポートを提供します。

Qualt構文解析画面

意味解析

意味解析では、スコープに従った識別子の実体確定と型エラーチェックを実施。さらに、データベース・テーブルのスキーマや統計情報を活用し、ユーザー定義の制約チェックや言語サポートを実現します。

セマンティック情報の構成

意味解析によって生成されるセマンティック情報は以下の3つで構成されます。

  • トークンごとのセマンティック情報: 各トークンの意味、型、参照先などを保持
  • 変数テーブル: スコープごとの変数・パラメータの定義と型情報
  • モジュールのデータ型: モジュール(クエリ、テーブル定義など)が出力するスキーマ情報

増分解析による高速化

データベース状態は刻々と変化するため、コード変更とは独立したサイクルでデータベース情報を更新する設計となっています。

コードに変更がある場合、セマンティック情報は各モジュール(exsqlファイル)ごとに保持され、モジュール間の依存関係グラフから変更があったモジュールとその依存モジュールのみを再計算の対象とします。これにより、大規模プロジェクトでも高速な型チェックと言語サポートを実現します。

セマンティック情報の例

SELECT order_id, num_of_item FROM ranged_orders()

上記クエリのASTノードに対して、以下のようなセマンティック情報が付与されます。

ASTノードノード種別データ型参照先・解決方法
SELECT order_id, num_of_item FROM ranged_orders()SELECT文TABLE(order_id INT64, num_of_item INT64)-
└ order_idフィールド参照INT64ranged_ordersの変数テーブルから解決
└ num_of_itemフィールド参照INT64ranged_ordersの変数テーブルから解決
└ FROM ranged_orders()FROM句TABLE(order_id INT64, num_of_item INT64)-
└ ranged_orders()モジュール呼び出しTABLE(order_id INT64, num_of_item INT64)module:ranged_orders
└ ranged_ordersモジュール参照MODULE定義済みモジュール
└ ()パラメータリスト-デフォルトパラメータで実行

SQLの柔軟性はそのままに、チーム開発のための新しいクエリ言語