リレーショナルデータベースを使用していると、項目ごとの表形式で結果を取得することが多いと思います。
直近の業務で取得した結果を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 句とは
対応内容
下記のような 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 の学習を行っている方の参考になれば幸いです。
執筆担当者プロフィール