I am trying to write a query to UNION
together objects from two related tables and return the Azure SQL Server results as JSON objects. I ran into an issue with the query that I cannot seem to resolve.
When I query the entity
table with a sub-object grades
list using the FOR JSON PATH
option to return JSON-formatted objects, i get the expected result.
Query
SELECT
entity.name AS name,
(
SELECT
grade_translation.name,
grade_translation.short_name
FROM
entity_grades,
grade,
grade_translation,
language
WHERE
entity.id = entity_grades.entity_id
AND entity_grades.grade_id = grade.id
AND grade.id = grade_translation.non_translated_id
AND grade_translation.language_id = language.id
AND language.short_name = 'en'
ORDER BY
entity_grades.[order]
FOR JSON PATH
) AS grades
FROM entity
LEFT JOIN entity_translation ON entity_translation.non_translated_id = entity.id
LEFT JOIN language ON language.id = entity_translation.language_id
WHERE language.short_name = 'en'
FOR JSON PATH
Result
[{
"name": "Test Entity 1",
"about": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Porta lorem mollis aliquam ut porttitor leo. Lacus sed viverra tellus in hac habitasse.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Integer malesuada nunc vel risus commodo. Neque aliquam vestibulum morbi blandit cursus risus.",
"grades": [{
"name": "Grade 9",
"short_name": "9"
}, {
"name": "Grade 10",
"short_name": "10"
}, {
"name": "Grade 11",
"short_name": "11"
}, {
"name": "Grade 12",
"short_name": "12"
}]
}, {
"name": "Test Entity 2",
"about": "Blah blah blah"
}]
Same goes for the objects that do not have translations.
Query (entities without translations)
SELECT
entity.name AS name,
(
SELECT
grade_translation.name,
grade_translation.short_name
FROM
entity_grades,
grade,
grade_translation,
language
WHERE
entity.id = entity_grades.entity_id
AND entity_grades.grade_id = grade.id
AND grade.id = grade_translation.non_translated_id
AND grade_translation.language_id = language.id
AND language.short_name = 'en'
ORDER BY
entity_grades.[order]
FOR JSON PATH
) AS grades
FROM entity
LEFT JOIN entity_translation ON entity_translation.non_translated_id = entity.id
LEFT JOIN language ON language.id = entity_translation.language_id
WHERE entity.id NOT IN (SELECT DISTINCT entity_translation.non_translated_id FROM entity_translation)
FOR JSON PATH
Result
[{
"name": "Test Entity 3"
}]
But when i UNION those two queries together, i get a grades
array that is escaped.
Query (UNION)
SELECT
entity.name AS name,
(
SELECT
grade_translation.name,
grade_translation.short_name
FROM
entity_grades,
grade,
grade_translation,
language
WHERE
entity.id = entity_grades.entity_id
AND entity_grades.grade_id = grade.id
AND grade.id = grade_translation.non_translated_id
AND grade_translation.language_id = language.id
AND language.short_name = 'en'
ORDER BY
entity_grades.[order]
FOR JSON PATH
) AS grades
FROM entity
LEFT JOIN entity_translation ON entity_translation.non_translated_id = entity.id
LEFT JOIN language ON language.id = entity_translation.language_id
WHERE language.short_name = 'en'
UNION
SELECT
entity.name AS name,
(
SELECT
grade_translation.name,
grade_translation.short_name
FROM
entity_grades,
grade,
grade_translation,
language
WHERE
entity.id = entity_grades.entity_id
AND entity_grades.grade_id = grade.id
AND grade.id = grade_translation.non_translated_id
AND grade_translation.language_id = language.id
AND language.short_name = 'en'
ORDER BY
entity_grades.[order]
FOR JSON PATH
) AS grades
FROM entity
LEFT JOIN entity_translation ON entity_translation.non_translated_id = entity.id
LEFT JOIN language ON language.id = entity_translation.language_id
WHERE entity.id NOT IN (SELECT DISTINCT entity_translation.non_translated_id FROM entity_translation)
FOR JSON PATH
Result
[{
"name": "Test Entity 1",
"about": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Porta lorem mollis aliquam ut porttitor leo. Lacus sed viverra tellus in hac habitasse.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Integer malesuada nunc vel risus commodo. Neque aliquam vestibulum morbi blandit cursus risus.",
"grades": "[{\"name\":\"Grade 9\",\"short_name\":\"9\"},{\"name\":\"Grade 10\",\"short_name\":\"10\"},{\"name\":\"Grade 11\",\"short_name\":\"11\"},{\"name\":\"Grade 12\",\"short_name\":\"12\"},{\"name\":\"Adult\",\"short_name\":\"AD\"}]"
}, {
"name": "Test Entity 2",
"about": "Blah blah blah"
}, {
"name": "Test Entity 3"
}]
I have tried wrapping the inner SELECT
statements with JSON_QUERY
as suggested in the following reference, but that had no effect.
Ref: How do I keep FOR JSON PATH from escaping query results?
Query with JSON_QUERY wrapping function
SELECT
entity.name AS name,
JSON_QUERY((
SELECT
grade_translation.name,
grade_translation.short_name
FROM
entity_grades,
grade,
grade_translation,
language
WHERE
entity.id = entity_grades.entity_id
AND entity_grades.grade_id = grade.id
AND grade.id = grade_translation.non_translated_id
AND grade_translation.language_id = language.id
AND language.short_name = 'en'
ORDER BY
entity_grades.[order]
FOR JSON PATH
)) AS grades
FROM entity
LEFT JOIN entity_translation ON entity_translation.non_translated_id = entity.id
LEFT JOIN language ON language.id = entity_translation.language_id
WHERE language.short_name = 'en'
UNION
SELECT
entity.name AS name,
JSON_QUERY((
SELECT
grade_translation.name,
grade_translation.short_name
FROM
entity_grades,
grade,
grade_translation,
language
WHERE
entity.id = entity_grades.entity_id
AND entity_grades.grade_id = grade.id
AND grade.id = grade_translation.non_translated_id
AND grade_translation.language_id = language.id
AND language.short_name = 'en'
ORDER BY
entity_grades.[order]
FOR JSON PATH
)) AS grades
FROM entity
LEFT JOIN entity_translation ON entity_translation.non_translated_id = entity.id
LEFT JOIN language ON language.id = entity_translation.language_id
WHERE entity.id NOT IN (SELECT DISTINCT entity_translation.non_translated_id FROM entity_translation)
FOR JSON PATH
Is there anything else i can try to return proper JSON from this style of query? Can someone explain whether this is a feature or a bug?