SQL フォーマット

SQL 文のフォーマットと整形ツール

ツール概要:SQL フォーマットツール

SQL(Structured Query Language)は、リレーショナルデータベースの管理と操作に使用される標準的な言語です。このツールは、SQL文の整形、美化、圧縮を行い、コードの可読性と保守性を向上させます。

SQL フォーマットツールとは?

SQL フォーマットツールは内容を整形し、読みやすいインデントとレイアウトに整えます。

使い方

  1. 整形したい内容を貼り付けます。
  2. インデントや整形オプションを選択します。
  3. 整形してコピーします。

よくある利用シーン

  • 公開前のスタイル統一
  • 構造や構文の問題の発見
  • ドキュメントでのきれいな表示

❓ よくある質問

Q1: 整形に失敗する?
A: 整形前に構文を確認してください。

Q2: 圧縮できますか?
A: 利用可能ならコンパクト表示を使ってください。

Q3: コメントは残せる?
A: コメント保持モードを選択してください。

✨ 主な機能

  • 🎨 自動整形:SQL文を読みやすい形式に自動フォーマット
  • 🗜️ コード圧縮:不要な空白や改行を削除してファイルサイズを削減
  • 構文検証:基本的なSQL構文エラーを検出
  • 📋 ワンクリックコピー:整形されたSQLを直接コピー可能
  • 🔧 カスタマイズ:インデントスタイルや改行設定を調整可能

📖 使用例

基本的なSELECT文の整形

整形前:

select u.id,u.name,u.email,p.title from users u join posts p on u.id=p.user_id where u.active=1 and p.published=1 order by p.created_at desc limit 10;

整形後:

SELECT 
    u.id,
    u.name,
    u.email,
    p.title
FROM users u
JOIN posts p ON u.id = p.user_id
WHERE u.active = 1
    AND p.published = 1
ORDER BY p.created_at DESC
LIMIT 10;

複雑なクエリの整形

整形前:

with monthly_sales as(select date_trunc('month',order_date)as month,sum(total_amount)as total_sales from orders where order_date>=current_date-interval'12 months'group by date_trunc('month',order_date)),avg_sales as(select avg(total_sales)as avg_monthly_sales from monthly_sales)select m.month,m.total_sales,a.avg_monthly_sales,case when m.total_sales>a.avg_monthly_sales then'Above Average'else'Below Average'end as performance from monthly_sales m cross join avg_sales a order by m.month;

整形後:

WITH monthly_sales AS (
    SELECT 
        DATE_TRUNC('month', order_date) AS month,
        SUM(total_amount) AS total_sales
    FROM orders
    WHERE order_date >= CURRENT_DATE - INTERVAL '12 months'
    GROUP BY DATE_TRUNC('month', order_date)
),
avg_sales AS (
    SELECT AVG(total_sales) AS avg_monthly_sales
    FROM monthly_sales
)
SELECT 
    m.month,
    m.total_sales,
    a.avg_monthly_sales,
    CASE 
        WHEN m.total_sales > a.avg_monthly_sales THEN 'Above Average'
        ELSE 'Below Average'
    END AS performance
FROM monthly_sales m
CROSS JOIN avg_sales a
ORDER BY m.month;

🎯 応用シーン

1. データベース開発

開発チームでのSQL標準化:

-- チーム標準のフォーマット例

-- ユーザー情報と投稿数の取得
SELECT 
    u.id AS user_id,
    u.username,
    u.email,
    u.created_at AS registration_date,
    COUNT(p.id) AS post_count,
    MAX(p.created_at) AS last_post_date
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
WHERE u.status = 'active'
    AND u.created_at >= '2024-01-01'
GROUP BY 
    u.id,
    u.username,
    u.email,
    u.created_at
HAVING COUNT(p.id) > 0
ORDER BY 
    post_count DESC,
    u.username ASC
LIMIT 50;

-- 売上分析クエリ
WITH daily_sales AS (
    SELECT 
        DATE(order_date) AS sale_date,
        SUM(total_amount) AS daily_total,
        COUNT(*) AS order_count,
        AVG(total_amount) AS avg_order_value
    FROM orders
    WHERE order_date >= CURRENT_DATE - INTERVAL '30 days'
        AND status = 'completed'
    GROUP BY DATE(order_date)
),
sales_with_trend AS (
    SELECT 
        *,
        LAG(daily_total) OVER (ORDER BY sale_date) AS prev_day_total,
        AVG(daily_total) OVER (
            ORDER BY sale_date 
            ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
        ) AS seven_day_avg
    FROM daily_sales
)
SELECT 
    sale_date,
    daily_total,
    order_count,
    avg_order_value,
    ROUND(
        ((daily_total - prev_day_total) / prev_day_total * 100), 2
    ) AS day_over_day_growth,
    ROUND(seven_day_avg, 2) AS seven_day_moving_avg
FROM sales_with_trend
ORDER BY sale_date DESC;

2. パフォーマンス最適化

クエリの可読性向上とパフォーマンス分析:

-- 最適化前のクエリ
SELECT * FROM orders o, customers c, products p, order_items oi 
WHERE o.customer_id = c.id AND oi.order_id = o.id AND oi.product_id = p.id 
AND o.order_date > '2024-01-01' AND c.country = 'Japan' AND p.category = 'Electronics';

-- 最適化後のクエリ(整形済み)
SELECT 
    o.id AS order_id,
    o.order_date,
    o.total_amount,
    c.name AS customer_name,
    c.email AS customer_email,
    p.name AS product_name,
    p.price AS product_price,
    oi.quantity,
    oi.unit_price
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id
INNER JOIN order_items oi ON oi.order_id = o.id
INNER JOIN products p ON oi.product_id = p.id
WHERE o.order_date > '2024-01-01'
    AND c.country = 'Japan'
    AND p.category = 'Electronics'
ORDER BY o.order_date DESC;

-- インデックス最適化のためのクエリ分析
EXPLAIN (ANALYZE, BUFFERS) 
SELECT 
    c.name,
    COUNT(o.id) AS order_count,
    SUM(o.total_amount) AS total_spent
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
    AND o.order_date >= CURRENT_DATE - INTERVAL '1 year'
WHERE c.status = 'active'
GROUP BY c.id, c.name
HAVING SUM(o.total_amount) > 1000
ORDER BY total_spent DESC;

3. データマイグレーション

データベース移行時のSQL整理:

-- データ移行スクリプトの例

-- 1. 新しいテーブル構造の作成
CREATE TABLE users_new (
    id BIGSERIAL PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(255) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    first_name VARCHAR(100),
    last_name VARCHAR(100),
    phone VARCHAR(20),
    date_of_birth DATE,
    status VARCHAR(20) DEFAULT 'active',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    CONSTRAINT users_status_check 
        CHECK (status IN ('active', 'inactive', 'suspended')),
    CONSTRAINT users_email_format_check 
        CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$')
);

-- 2. データの移行
INSERT INTO users_new (
    username,
    email,
    password_hash,
    first_name,
    last_name,
    phone,
    status,
    created_at
)
SELECT 
    LOWER(TRIM(old_username)) AS username,
    LOWER(TRIM(old_email)) AS email,
    old_password AS password_hash,
    INITCAP(TRIM(old_fname)) AS first_name,
    INITCAP(TRIM(old_lname)) AS last_name,
    REGEXP_REPLACE(old_phone, '[^0-9+\-()]', '', 'g') AS phone,
    CASE 
        WHEN old_active = 1 THEN 'active'
        WHEN old_active = 0 THEN 'inactive'
        ELSE 'suspended'
    END AS status,
    old_created_date AS created_at
FROM users_old
WHERE old_email IS NOT NULL
    AND old_email != ''
    AND old_username IS NOT NULL
    AND old_username != '';

-- 3. データ整合性の確認
SELECT 
    'users_old' AS table_name,
    COUNT(*) AS record_count
FROM users_old
WHERE old_email IS NOT NULL AND old_email != ''

UNION ALL

SELECT 
    'users_new' AS table_name,
    COUNT(*) AS record_count
FROM users_new;

-- 4. 重複データの確認
SELECT 
    email,
    COUNT(*) AS duplicate_count
FROM users_new
GROUP BY email
HAVING COUNT(*) > 1
ORDER BY duplicate_count DESC;

4. レポート生成

ビジネスレポート用のSQL整理:

-- 月次売上レポート
WITH monthly_metrics AS (
    SELECT 
        DATE_TRUNC('month', order_date) AS month,
        COUNT(DISTINCT customer_id) AS unique_customers,
        COUNT(*) AS total_orders,
        SUM(total_amount) AS total_revenue,
        AVG(total_amount) AS avg_order_value,
        MIN(total_amount) AS min_order_value,
        MAX(total_amount) AS max_order_value
    FROM orders
    WHERE order_date >= CURRENT_DATE - INTERVAL '12 months'
        AND status = 'completed'
    GROUP BY DATE_TRUNC('month', order_date)
),
monthly_growth AS (
    SELECT 
        *,
        LAG(total_revenue) OVER (ORDER BY month) AS prev_month_revenue,
        LAG(unique_customers) OVER (ORDER BY month) AS prev_month_customers
    FROM monthly_metrics
)
SELECT 
    TO_CHAR(month, 'YYYY-MM') AS month_year,
    unique_customers,
    total_orders,
    ROUND(total_revenue, 2) AS total_revenue,
    ROUND(avg_order_value, 2) AS avg_order_value,
    ROUND(
        CASE 
            WHEN prev_month_revenue > 0 THEN
                ((total_revenue - prev_month_revenue) / prev_month_revenue * 100)
            ELSE 0
        END, 2
    ) AS revenue_growth_percent,
    ROUND(
        CASE 
            WHEN prev_month_customers > 0 THEN
                ((unique_customers - prev_month_customers) / prev_month_customers * 100)
            ELSE 0
        END, 2
    ) AS customer_growth_percent
FROM monthly_growth
ORDER BY month DESC;

-- 商品カテゴリ別分析
SELECT 
    p.category,
    COUNT(DISTINCT p.id) AS product_count,
    COUNT(oi.id) AS total_sales,
    SUM(oi.quantity) AS total_quantity_sold,
    SUM(oi.quantity * oi.unit_price) AS total_revenue,
    ROUND(AVG(oi.unit_price), 2) AS avg_unit_price,
    ROUND(
        SUM(oi.quantity * oi.unit_price) / 
        SUM(SUM(oi.quantity * oi.unit_price)) OVER () * 100, 2
    ) AS revenue_percentage
FROM products p
INNER JOIN order_items oi ON p.id = oi.product_id
INNER JOIN orders o ON oi.order_id = o.id
WHERE o.order_date >= CURRENT_DATE - INTERVAL '3 months'
    AND o.status = 'completed'
GROUP BY p.category
ORDER BY total_revenue DESC;

🔧 技術詳細

フォーマット規則

SQL整形の基本規則:

キーワード:

  • SELECT、FROM、WHERE等は大文字
  • 各主要句は新しい行から開始
  • サブクエリは適切にインデント

インデント:

  • 2スペースまたは4スペースで統一
  • ネストしたクエリは追加インデント
  • カラムリストは縦に整列

改行:

  • 長いクエリは論理的な単位で改行
  • JON条件は読みやすく配置
  • CASE文は構造化して表示

データベース方言対応

-- PostgreSQL固有の機能
SELECT 
    id,
    name,
    created_at::DATE AS creation_date,
    EXTRACT(YEAR FROM created_at) AS creation_year
FROM users
WHERE created_at >= CURRENT_DATE - INTERVAL '1 month';

-- MySQL固有の機能
SELECT 
    id,
    name,
    DATE(created_at) AS creation_date,
    YEAR(created_at) AS creation_year
FROM users
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH);

-- SQL Server固有の機能
SELECT 
    id,
    name,
    CAST(created_at AS DATE) AS creation_date,
    YEAR(created_at) AS creation_year
FROM users
WHERE created_at >= DATEADD(MONTH, -1, GETDATE());

💡 使用のコツ

  • 一貫性:チーム内でフォーマット規則を統一
  • 可読性:複雑なクエリは適切にコメントを追加
  • パフォーマンス:整形後もクエリ性能を確認
  • バージョン管理:整形されたSQLをバージョン管理システムで管理

⚠️ 注意事項

  • 構文エラー:整形前にSQL構文が正しいことを確認
  • データベース方言:使用するデータベースの方言に注意
  • パフォーマンス:整形がクエリ性能に影響しないことを確認
  • バックアップ:重要なクエリは整形前にバックアップを作成

🚀 使い方

  1. SQL入力:整形したいSQL文を入力ボックスに貼り付け
  2. オプション選択:「整形」または「圧縮」を選択
  3. 実行:ボタンをクリックして処理を実行
  4. 結果確認:整形されたSQLが出力エリアに表示
  5. コピー使用:「コピー」ボタンで結果をクリップボードにコピー

ヒント:このツールはクライアント側でローカル処理を行い、SQLクエリをサーバーに送信しないため、機密性の高いクエリも安全に整形できます。