FOR JSON PATH返回嵌套对象的转义字符串

时间:2019-04-01 20:53:34

标签: sql json sql-server azure-sql-database union

我试图将来自两个相关表的对象一起写到UNION的查询,并将Azure SQL Server结果作为JSON对象返回。我遇到了我似乎无法解决的查询问题。

当我使用entity选项用子对象grades列表查询FOR JSON PATH表以返回JSON格式的对象时,我得到了预期的结果。

查询

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

结果

[{
    "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"
}]

没有翻译的对象也一样。

查询(不含翻译的实体)

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

结果

[{
    "name": "Test Entity 3"
}]

但是当我将这两个查询联合在一起时,我得到了一个转义的grades数组。

查询(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

结果

[{
    "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"
}]

我已尝试按照以下参考文献中的建议用SELECT包裹内部JSON_QUERY语句,但这没有效果。

参考:How do I keep FOR JSON PATH from escaping query results?

使用JSON_QUERY包装函数进行查询

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

还有什么我可以尝试从这种查询样式返回正确的JSON吗?有人可以解释这是功能还是错误?

1 个答案:

答案 0 :(得分:0)

我通过完全消除UNION解决了这一问题。在这种情况下,这就像向第一个查询添加WHERE … OR language.short_name IS NULL一样简单。