T-SQL でクエリの結果を JSON 文字列に変換する - FOR JSON AUTO
T-SQL でクエリの結果を JSON 文字列へ
SQL Server の 2016 以降では、組み込みの JSON ファンクションが提供されて、簡単に T-SQL でクエリの結果を JSON 文字列に変換したり、JSON 文字列を解析して、値を取得したりクエリーを書いたりできるようになりました。
今回は、T-SQL でクエリの結果を JSON 文字列に変換してみたいと思います。
クエリーの結果を FOR JSON で JSON 形式の文字列へ
クエリーの結果を JSON 形式の文字列にフォーマットするには、FOR JSON 句を SELECT 文に追加します。
FOR JSON には、FOR JSON AUTO と FOR JSON PATH があります。
FOR JSON AUTO は、SELECT 文の構造に応じて、クエリーの結果を自動的に JSON 形式に変換します。
SELECT 句で何も指定しなくてもいいので、てっとり早いですが、プロパティーのキー名や階層など、細かい指定はできません。
FOR JSON PATH のほうは、オブジェクトをネストさせたり、いろいろと自由に制御することができます。
JSON を扱いたいような状況では、FOR JSON PATH を使っていろいろと制御して、JSON 文字列を生成しなければならないケースのほうが多いのではないかな?と思います。
FOR JSON AUTO
それでは、まず FOR JSON AUTO の出力例を見てみましょう。
次のような Student テーブルと TestResult テーブルがあります。
このようなクエリーの結果を、JSON 文字列に変換してみます。
※ サンプルデータを生成するスクリプトは こちら にありますが、同じ名前のテーブルが既に存在している場合、削除されてしまうのでご注意ください。
FOR JSON AUTO をつかって、自動的に JSON 形式に変換された文字列を取得するクエリーは以下の通りです。
SELECT TOP 2 S.StudentID, S.FirstName, S.LastName, TR.TestResultCount, TR.ScoreAverage FROM Student AS S INNER JOIN (SELECT StudentID, COUNT(Score) AS TestResultCount, AVG(CAST(Score AS DECIMAL)) AS ScoreAverage FROM TestResult GROUP BY StudentID) AS TR ON S.StudentID = TR.StudentID ORDER BY TR.ScoreAverage DESC FOR JSON AUTO;
[ 実行結果 ]
結果はテキストに出力しています。
ちなみに結果をグリッドに出力すると、次のように JSON 文字列がリンク付きで表示され、クリックすると別画面が開いて文字列が表示されます。

得られた JSON の文字列を読みやすいように改行すると次のようになります。
[
{
"StudentID":3,
"FirstName":"Yuko",
"LastName":"Suzuki",
"TR":[
{
"TestResultCount":1,
"ScoreAverage":92.000000
}
]
},
{
"StudentID":4,
"FirstName":"Takao",
"LastName":"Sato",
"TR":[
{
"TestResultCount":2,
"ScoreAverage":89.500000
}
]
}
]
試しにもうひとつ、次のようなクエリーを変換してみます。
SELECT TOP 2 S.StudentID, S.FirstName, S.LastName, T.TestNameEn, TR.Score FROM Student AS S INNER JOIN TestResult AS TR ON S.StudentID = TR.StudentID INNER JOIN Test AS T ON TR.TestID = T.TestID WHERE T.TestID = 1 ORDER BY TR.Score DESC FOR JSON AUTO;
[ 実行結果 ]
[
{
"StudentID":4,
"FirstName":"Takao",
"LastName":"Sato",
"T":[
{
"TestNameEn":"Math 1",
"TR":[
{
"Score":98
}
]
}
]
},
{
"StudentID":1,
"FirstName":"Taro",
"LastName":"Yamada",
"T":[
{
"TestNameEn":"Math 1",
"TR":[
{
"Score":85
}
]
}
]
}
]
要素数は行数と同じで、カラム名がプロパティーのキー名になります。
JOIN した場合はテーブル名やテーブルのエイリアスがプロパティーのキーになり、オブジェクトがネストされます。
すごくシンプルな SELECT 文に使う時はよさそうですが、複雑なクエリー結果に使う時は、期待通りにフォーマットされた JSON 文字列 が返ってくるか少しわかりにくいので、FOR JSON PATH で自分で制御したほうが良いかもしれません。