sql-server - 如何防止 FOR JSON PATH 转义查询结果?

标签 sql-server json

我正在尝试编写一个相当复杂的 SQL 查询,生成 JSON 作为结果。一切都工作得很好,除了一些硬编码数组,我需要在层次结构中更深入,我必须使用 UNION ALL创造。我生成了一个查询,在此处显示了我的问题(不需要数据 - 我在 Azure SQL 数据库中运行此查询):

SELECT
    'Hi' AS Greeting,
    (
        SELECT
            CASE WHEN DatePart(second, GetDate()) % 2 = 1 THEN
                'qwerty'
            ELSE
                'asdf'
            END AS Stuff
        FOR JSON PATH
    ) AS StuffArray,
    (
        CASE WHEN DatePart(second, GetDate()) % 2 = 1 THEN
        (
            SELECT 'qwerty' AS Stuff
            FOR JSON PATH
        )
        ELSE
        (
            SELECT 'asdf' AS Stuff
            FOR JSON PATH
        )
        END
    ) AS QuotedStuffArray,
    (
        CASE WHEN DatePart(second, GetDate()) % 2 = 1 THEN
        (
            SELECT * FROM
            (
                SELECT 'qwerty' AS Stuff
                UNION ALL
                SELECT 'zxcvb' AS Stuff
            ) AS SubSelect
            FOR JSON PATH
        )
        ELSE
        (
            SELECT 'asdf' AS Stuff
            FOR JSON PATH
        )
        END
    ) AS WhyItMatters,
    (
        SELECT * FROM
        (
            SELECT 'qwerty' AS Stuff
            UNION ALL
            SELECT 'zxcvb' AS Stuff
        ) AS SubSelect
        FOR JSON PATH
    ) AS ButThisIsFine
FOR JSON PATH

这将输出此 JSON:

[
    {
        "Greeting": "Hi",
        "StuffArray": [
            {
                "Stuff": "qwerty"
            }
        ],
        "QuotedStuffArray": "[{\"Stuff\":\"qwerty\"}]",
        "WhyItMatters": "[{\"Stuff\":\"qwerty\"},{\"Stuff\":\"zxcvb\"}]",
        "ButThisIsFine": [
            {
                "Stuff": "qwerty"
            },
            {
                "Stuff": "zxcvb"
            }
        ]
    }
]

在此查询中,您将在基础对象之外的层次结构中看到四个不同的对象: StuffArray , QuotedStuffArray , WhyItMatters ,和ButThisIsFineStuffArray object 正是我想要的所有对象的样子 - 纯 JSON,没有任何转义。然而,当我开始把我的SELECT我的 CASE 内的语法声明后,我的结果开始被引用,如QuotedStuffArray所示目的。所以对于前两个对象来说,这很好。但我有一个问题,有时需要执行条件 UNION两个硬编码值迫使我将 SELECT进入CASE声明如WhyItMatters所示目的。 ButThisIsFine对象生成的输出格式就像我想要的 WhyItMatters要格式化的对象,但它删除了条件 UNION ,我需要。

我怎样才能得到最后这个WhyItMatters对象生成没有转义引号的纯 JSON,就像 ButThisIsFine 一样对象,同时保持该条件 UNION声明?

最佳答案

此查询的优化器中发生了一些令人着迷的行为,我不确定这是否是一个错误。以下查询将不会添加转义:

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

CASE 可以被优化掉,并且它优化掉,最终结果是很好的嵌套 JSON。但是,如果我们删除优化功能,它就会退化为粘贴转义字符串:

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

一个查询会导致处理类型化 JSON,而另一个查询则不会,这似乎不合逻辑,但就是这样。 JSON 不是 T-SQL 中的实际类型(与 XML 不同),因此我们无法进行 CASTCONVERT >,但是 JSON_QUERY 会做大致相同的事情:

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

请注意,如果参数已经是 JSON(在常量情况下),这也适用,因此无论如何添加都是安全的。

关于sql-server - 如何防止 FOR JSON PATH 转义查询结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45927168/

相关文章:

SQL完全清空数据库

sql - 如何更新表中的所有行并增加一列?

java - 如何在Spring框架中的Hibernate一对多关系中仅从父类获取json数据

mysql - 从 MySQL 中提取所有 JSON 键

mysql - 将 ID 链接到表 SQL 中的其他 ID

c# - 加速 SqlDataSource 的技巧?

sql-server - 了解脚本组件如何更新数据库中的数据

ruby-on-rails - 更新 Rails 4 和 PostgreSQL json 列中的单个键/值对?

javascript - 将包含字符串数据的变量转换为 JavaScript REST API 的 JSON 对象

python - 不是 JSON 可序列化的