【SQL】SQL Server で取得結果を1行にまとめて出力する

リレーショナルデータベースを使用していると、項目ごとの表形式で結果を取得することが多いと思います。

直近の業務で取得した結果を1 行でまとめたいことがあったため、その方法を記事でご紹介します。

対応概要

システムへの登録を行っていない社員を抽出し、各担当者へメール通知する改修がありました。

システムでは下記のようなテーブルを使用しており、ここから対象者を抽出します。

TblRegist(登録テーブル)

No Dept Member RegistFlg
1 人事 人事 一郎 0
2 人事 人事 二郎 0
3 総務 総務 A子 0
4 総務 総務 B子 0
5 人事 人事 三郎 0
6 経理 経理 太郎 0
7 経理 経理 次郎 1

メール本文には該当部署の対象メンバーを記載し送信します。

また、システムの都合上、メール本文の整形時に複雑なロジックを入れることが難しかったため、できるだけメール送信時の本文に近い形でデータを取得したい状況でした。

環境

今回対応を行ったのは下記の環境になります。

  • Microsoft SQL Server 2017
  • SQL Server Management Studio

対応案

SQL Server のFOR XML句を使用して1 行でデータを取得し、処理では取得データに対する繰り返しと置換を使用してメール本文を加工しました。

FOR XML 句とは

learn.microsoft.com

対応内容

下記のような SQL で部署ごとに対象者を1 行にまとめました。

また、取得結果の |を改行に置換することでMembersを1 行ずつメール本文に出力する対応を行いました。

SQL

SELECT
     Dept
    ,(
        SELECT
            '|' + temp.Member
        FROM
            TblRegister AS temp
        WHERE
            temp.Dept = tl.Dept
            AND RegistFlg = '0'
        ORDER BY
            temp.No
        FOR XML PATH('')
     ) AS Members
FROM
    (
        SELECT DISTINCT
             Dept
        FROM
             TblRegister
        WHERE
             RegistFlg = '0'
    ) AS tl

取得結果

Dept Members
経理 |経理 太郎
人事 |人事 一郎|人事 二郎|人事 三郎
総務 |総務 A子|総務 B子

追記

他のデータベースでも下記を使用して同様の処理が可能なようです。

データベース 関数
Oracle LISTAGG 関数
MySQL GROUP_CONCAT 関数
PostgreSQL string_agg

おわりに

普段あまり使用しない関数を使い、勉強になりました。

同様の処理を検討している方や SQL の学習を行っている方の参考になれば幸いです。

執筆担当者プロフィール
石橋 侑樹

石橋 侑樹(日本ビジネスシステムズ株式会社)

これまで業務システムやWebアプリの開発、業務自動化等に携わってきました。サッカーが好きで休日は試合を見ていることが多いです。

担当記事一覧