I\'m trying to write a fairly complicated SQL Query that produces JSON as the result. All is working great except for some hardcoded arrays I need to have deeper in the hier
There's some fascinating behavior going on in the optimizer for this query, and I'm not sure if it's a bug. The following query will not add escaping:
SELECT
'Hi' AS Greeting,
(
CASE WHEN 1 = 1 THEN (
SELECT * FROM (
SELECT 'qwerty' AS [Stuff]
UNION ALL
SELECT 'zxcvb' AS [Stuff]
) _
FOR JSON PATH
) ELSE (
SELECT 'asdf' AS [Stuff]
FOR JSON PATH
)
END
) AS WhyItMatters
FOR JSON PATH
The CASE can be optimized away, and it is optimized away, and the end result is nicely nested JSON. But if we remove the ability to optimize things away, it degenerates into pasting in an escaped string:
SELECT
'Hi' AS Greeting,
(
CASE WHEN RAND() = 1 THEN (
SELECT * FROM (
SELECT 'qwerty' AS [Stuff]
UNION ALL
SELECT 'zxcvb' AS [Stuff]
) _
FOR JSON PATH
) ELSE (
SELECT 'asdf' AS [Stuff]
FOR JSON PATH
)
END
) AS WhyItMatters
FOR JSON PATH
It seems illogical that one query would result in processing typed JSON and the other would not, but there you go. JSON is not an actual type in T-SQL (unlike XML), so we can't CAST or CONVERT, but JSON_QUERY will do roughly the same thing:
SELECT
'Hi' AS Greeting,
JSON_QUERY(
CASE WHEN RAND() = 1 THEN (
SELECT * FROM (
SELECT 'qwerty' AS [Stuff]
UNION ALL
SELECT 'zxcvb' AS [Stuff]
) _
FOR JSON PATH
) ELSE (
SELECT 'asdf' AS [Stuff]
FOR JSON PATH
)
END
) AS WhyItMatters
FOR JSON PATH
Note that this also works if the argument is already JSON (in the constant case), so it's safe to add regardless.