SQL Server支持将扁平的表格式SQL结果集转化为分层结构,通过使用方便的 FOR XML
或 FOR JSON
语法。这确实很方便,而且比标准的SQL/XML或SQL/JSON API不那么啰嗦--尽管标准的API更强大。 在这篇博文中,我想展示SQL Server语法的几个核心特性,以及它们在标准SQL中的对应关系。jOOQ 3.14将同时支持SQL Server的语法和标准语法,并且能够从一个翻译到另一个,这样你就可以在Db2、MariaDB、MySQL、Oracle、PostgreSQL上使用SQL Server语法。你可以在我们的网站上玩一玩当前的开发状态,这里。 像往常一样,使用Sakila数据库,这里有一个简单的例子作为引子:
-- SQL Server
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
FOR XML RAW;
-- Db2, Oracle, PostgreSQL
SELECT xmlagg(xmlelement(
NAME row,
xmlattributes(
t.first_name AS first_name,
t.last_name AS last_name,
t.title AS title
)
))
FROM (
-- Original query here
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
) AS t
在这两种情况下产生的东西是:
<row first_name="PENELOPE" last_name="GUINESS" title="OKLAHOMA JUMANJI"/>
<row first_name="PENELOPE" last_name="GUINESS" title="RULES HUMAN"/>
<row first_name="PENELOPE" last_name="GUINESS" title="SPLASH GUMP"/>
<row first_name="PENELOPE" last_name="GUINESS" title="VERTIGO NORTHWEST"/>
<row first_name="PENELOPE" last_name="GUINESS" title="WESTWARD SEABISCUIT"/>
<row first_name="PENELOPE" last_name="GUINESS" title="WIZARD COLDBLOODED"/>
<row first_name="NICK" last_name="WAHLBERG" title="ADAPTATION HOLES"/>
<row first_name="NICK" last_name="WAHLBERG" title="APACHE DIVINE"/>
FOR XML和FOR JSON的概念
从上面的预告中可以看出,SQL Server的语法远没有那么冗长和简洁,而且它似乎产生了一个合理的默认行为,而Db2、Oracle、PostgreSQL(和SQL标准)的SQL/XML APIs则更加冗长,但也更加强大。例如,可以非常容易地将列a映射到属性x,将列b映射到一个嵌套的XML元素y。 这两种方法的优点都很明显。在一般情况下,SQL Server的方法更可用。但什么是一般情况呢?让我们总结一下SQL结果集和XML/JSON数据结构之间的几个主要相似之处:
**表是XML元素或JSON数组**表(即数据集)对于XML和JSON文档来说都不是一个陌生的概念。在XML中表示一组数据的最自然的方式是一组使用相同元素名称的元素,可以选择用包装元素来包装。例如:
<!-- With wrapper element -->
<films>
<film title="OKLAHOMA JUMANJI"/>
<film title="RULES HUMAN"/>
<film title="SPLASH GUMP"/>
</films>
<!-- Without wrapper element -->
<film title="OKLAHOMA JUMANJI"/>
<film title="RULES HUMAN"/>
<film title="SPLASH GUMP"/>
在嵌套数据时,是否添加包装元素的区别是最重要的。 对于JSON,表示表格的数据结构的明显选择是一个数组。例如:
[
{"title": "OKLAHOMA JUMANJI"},
{"title": "RULES HUMAN"},
{"title": "SPLASH GUMP"}
]
**行是XML元素或JSON对象**正如我们上面已经看到的,一个SQL行在XML中用一个元素表示:
<film title="OKLAHOMA JUMANJI"/>
问题只是元素的名称应该是什么。它通常可以是以下任何一种:
- 一个标准名称,如 "行"
- 行的表的名称
- 一个自定义的名字
在JSON中,它是一个对象:
{"title": "OKLAHOMA JUMANJI"}
不像在XML中,没有所谓的元素名称,所以行是 "匿名的"。行的类型由JSON对象所包含的表/数组来定义。**列值是XML元素或属性,或JSON属性**我们对如何在XML中表示SQL列值有更多选择。主要有两种选择:
- 将值作为属性表示
- 以元素的形式表示数值
标量值可以很容易地被表示为属性。如果一个值需要进一步嵌套(如数组、用户定义的类型等),那么元素是一个更好的选择。在大多数情况下,这个选择并不重要,所以我们可以同时选择:
<!-- Using attributes -->
<film film_id="635" title="OKLAHOMA JUMANJI"/>
<!-- Using elements from table and column names -->
<film>
<film_id>635</film_id>
<title>OKLAHOMA JUMANJI</title>
</film>
<!-- Using standard element names
<row>
<value name="film_id" value="635"/>
<value name="title" value="OKLAHOMA JUMANJI"/>
</row>
在XML中,还有一些其他合理的默认选项来表示一个列值。 另一方面,在JSON中,有两种主要的合理方法。在大多数情况下,会选择一个对象,其中列值由列名识别。但就像SQL记录是 "结构体 "和 "图元 "的混合体一样,我们也可以想象一种将列值映射到数组索引的表示方法:
// Using objects
{"film_id": 635, "title": "OKLAHOMA JUMANJI"}
// Using arrays
[635, "OKLAHOMA JUMANJI"]
GROUP BY和ORDER BY可以被看作是一种嵌套数据的方式到目前为止,所有数据都是以平面方式表示的,就像SQL表一样。当用一些包装元素或对象包装JSON数组的XML元素时,或者用更多的元素而不是属性来表示XML数据时,有一些嵌套,但数据仍然总是表格式的。 不过很多时候,我们希望以分层的形式消费数据。一个演员在电影中演出,所以我们想按演员来分组,而不是为每部电影重复演员的信息。一般来说,像GROUP BY
或ORDER BY
这样的操作可以达到这个目的。GROUP BY
可以将所有数据汇总到每组的嵌套数据结构中(例如,汇总到字符串、数组、XML元素、JSON数组、JSON对象中)。ORDER BY
也是这样做的,"视觉上"--也许有点不那么正式。当我们看这组XML元素时,我们可以直观地看到它们是按行为者 "分组"(即排序)的:
<row first_name="PENELOPE" last_name="GUINESS" title="OKLAHOMA JUMANJI"/>
<row first_name="PENELOPE" last_name="GUINESS" title="RULES HUMAN"/>
<row first_name="PENELOPE" last_name="GUINESS" title="SPLASH GUMP"/>
<row first_name="PENELOPE" last_name="GUINESS" title="VERTIGO NORTHWEST"/>
<row first_name="PENELOPE" last_name="GUINESS" title="WESTWARD SEABISCUIT"/>
<row first_name="PENELOPE" last_name="GUINESS" title="WIZARD COLDBLOODED"/>
<row first_name="NICK" last_name="WAHLBERG" title="ADAPTATION HOLES"/>
<row first_name="NICK" last_name="WAHLBERG" title="APACHE DIVINE"/>
SQL Server至少以两种方式支持这种分组:
- 通过惯例隐式地使用
ORDER BY
- 通过创建相关的子查询来明确表示
隐式方法可以将上述平面表示法转化为这样的内容:
<a first_name="PENELOPE" last_name="GUINESS">
<f title="OKLAHOMA JUMANJI"/>
<f title="RULES HUMAN"/>
<f title="SPLASH GUMP"/>
<f title="VERTIGO NORTHWEST"/>
<f title="WESTWARD SEABISCUIT"/>
<f title="WIZARD COLDBLOODED"/>
</a>
<a first_name="NICK" last_name="WAHLBERG">
<f title="ADAPTATION HOLES"/>
<f title="APACHE DIVINE"/>
</a>
... 其中 "a "和 "f "是查询中的表名(actor a
和film f
)。
FOR XML和FOR JSON是如何详细工作的?
在SQL Server中,有几个功能可以结合起来。完整的情况可以从文档中看到。在这篇博文中,我们会省略一些功能:
- 转换算法
RAW
(平面结果,仅在XML中),AUTO
(分层的,自动的结果),PATH
(分层的,明确的结果) - 根 "名称,对应于一个XML封装元素,或一个JSON封装对象
- 仅限XML:值是否应放在
ELEMENTS
或属性中 - 仅限JSON:
INCLUDE_NULL_VALUES
指定NULL
值是显式的,还是隐式的(不在JSON对象中)。 - 仅限JSON:
WITHOUT_ARRAY_WRAPPER
指定JSON对象的集合是否应该以JSON数组的形式列出,或者以逗号分隔的对象列表(可以与其他查询结合)。
这并不完整,还有更多的标志和功能,但与其在理论上讨论它们,不如看看几个例子:FOR XML RAW产生带有属性值的平面结果
-- SQL Server
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR XML RAW;
-- Standard SQL
SELECT xmlagg(xmlelement(
NAME row,
xmlattributes(
t.first_name AS first_name,
t.last_name AS last_name,
t.title AS title
)
))
FROM (
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
) AS t
这将产生
<row first_name="NICK" last_name="WAHLBERG" title="SMILE EARRING"/>
<row first_name="NICK" last_name="WAHLBERG" title="WARDROBE PHANTOM"/>
<row first_name="PENELOPE" last_name="GUINESS" title="ACADEMY DINOSAUR"/>
<row first_name="PENELOPE" last_name="GUINESS" title="ANACONDA CONFESSIONS"/>
FOR XML RAW, ROOT产生带有属性值的平面结果,并有一个根元素来包裹所列元素
-- SQL Server
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR XML RAW, ROOT('rows');
-- Standard SQL
SELECT xmlelement(
NAME rows,
xmlagg(xmlelement(
NAME row,
xmlattributes(
t.first_name AS first_name,
t.last_name AS last_name,
t.title AS title
)
))
)
FROM (
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
) AS t
产生
<rows>
<row first_name="NICK" last_name="WAHLBERG" title="SMILE EARRING"/>
<row first_name="NICK" last_name="WAHLBERG" title="WARDROBE PHANTOM"/>
<row first_name="PENELOPE" last_name="GUINESS" title="ACADEMY DINOSAUR"/>
<row first_name="PENELOPE" last_name="GUINESS" title="ANACONDA CONFESSIONS"/>
</rows>
FOR XML RAW, ELEMENTS产生带有元素值的平面结果:
-- SQL Server
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR XML RAW, ELEMENTS;
-- Standard SQL
SELECT xmlagg(xmlelement(
NAME row,
xmlelement(
NAME first_name,
first_name
),
xmlelement(
NAME last_name,
last_name
),
xmlelement(
NAME title,
title
)
))
FROM (
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR XML RAW, ELEMENTS
) AS t
这就产生了
<row>
<first_name>NICK</first_name>
<last_name>WAHLBERG</last_name>
<title>SMILE EARRING</title>
</row>
<row>
<first_name>NICK</first_name>
<last_name>WAHLBERG</last_name>
<title>WARDROBE PHANTOM</title>
</row>
<row>
<first_name>PENELOPE</first_name>
<last_name>GUINESS</last_name>
<title>ACADEMY DINOSAUR</title>
</row>
<row>
<first_name>PENELOPE</first_name>
<last_name>GUINESS</last_name>
<title>ANACONDA CONFESSIONS</title>
</row>
这也可以和ROOT
,为了简洁起见,我们省略了这一点。FOR XML/JSON AUTO这种方法从你的查询结构中完全自动得出结果。主要是:
SELECT
子句定义了XML或JSON数据的嵌套顺序。FROM
子句定义了表名(通过别名),这些表名被翻译成XML元素或JSON对象属性名。ORDER BY
子句产生 "分组",它被翻译成嵌套的XML元素或JSON对象。
-- SQL Server
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR XML AUTO;
-- Standard SQL
SELECT xmlagg(e)
FROM (
SELECT xmlelement(
NAME a,
xmlattributes(
t.first_name AS first_name,
t.last_name AS last_name
),
xmlagg(xmlelement(
NAME f,
xmlattributes(t.title AS title)
))
) AS e
FROM (
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
) AS t
GROUP BY
first_name,
last_name
) AS t
请注意这种模拟需要两步XMLAGG
与GROUP BY
。随着更多的表被连接和投射,它变得更加毛糙!我不会在这里添加更复杂的例子,但可以在网上试试!这产生了:
<a first_name="NICK" last_name="WAHLBERG">
<f title="SMILE EARRING"/>
<f title="WARDROBE PHANTOM"/>
</a>
<a first_name="PENELOPE" last_name="GUINESS">
<f title="ACADEMY DINOSAUR"/>
<f title="ANACONDA CONFESSIONS"/>
</a>
让我们用JSON再次尝试同样的事情:
-- SQL Server
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR JSON AUTO;
-- Standard SQL
SELECT json_arrayagg(e)
FROM (
SELECT JSON_OBJECT(
KEY 'FIRST_NAME' VALUE first_name,
KEY 'LAST_NAME' VALUE last_name,
KEY 'F' VALUE JSON_ARRAYAGG(JSON_OBJECT(
KEY 'TITLE' VALUE title
ABSENT ON NULL
))
ABSENT ON NULL
) e
FROM (
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
) t
GROUP BY
first_name,
last_name
) t
结果是:
[
{
"first_name": "NICK",
"last_name": "WAHLBERG",
"f": [
{
"title": "SMILE EARRING"
},
{
"title": "WARDROBE PHANTOM"
}
]
},
{
"first_name": "PENELOPE",
"last_name": "GUINESS",
"f": [
{
"title": "ACADEMY DINOSAUR"
},
{
"title": "ANACONDA CONFESSIONS"
}
]
}
]
FOR XML/JSON AUTO, ROOT像以前一样,如果需要的话,我们可以用根XML元素或根JSON对象来包装它:
-- SQL Server
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR XML AUTO, ROOT;
-- Standard SQL
SELECT xmlelement(
NAME join,
xmlagg(e)
)
FROM (
SELECT xmlelement(
NAME a,
xmlattributes(
t.first_name AS first_name,
t.last_name AS last_name
),
xmlagg(xmlelement(
NAME f,
xmlattributes(t.title AS title)
))
) e
FROM (
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
) t
GROUP BY
first_name,
last_name
) t
这和之前做的事情一样,只是在另一个XMLELEMENT()
函数调用中包装了之前的根XMLAGG()
元素。这产生了
<root>
<a first_name="NICK" last_name="WAHLBERG">
<f title="SMILE EARRING"/>
<f title="WARDROBE PHANTOM"/>
</a>
<a first_name="PENELOPE" last_name="GUINESS">
<f title="ACADEMY DINOSAUR"/>
<f title="ANACONDA CONFESSIONS"/>
</a>
</root>
让我们再试试用JSON做同样的事情:
-- SQL Server
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR JSON AUTO, ROOT;
-- Standard SQL
SELECT JSON_OBJECT(KEY 'a' VALUE json_arrayagg(e))
FROM (
SELECT JSON_OBJECT(
KEY 'FIRST_NAME' VALUE first_name,
KEY 'LAST_NAME' VALUE last_name,
KEY 'F' VALUE JSON_ARRAY_AGG(JSON_OBJECT(
KEY 'TITLE' VALUE title
ABSENT ON NULL
))
ABSENT ON NULL
) e
FROM (
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
) t
GROUP BY
first_name,
last_name
) t
结果是:
{
"a": [
{
"first_name": "NICK",
"last_name": "WAHLBERG",
"f": [
{
"title": "SMILE EARRING"
},
{
"title": "WARDROBE PHANTOM"
}
]
},
{
"first_name": "PENELOPE",
"last_name": "GUINESS",
"f": [
{
"title": "ACADEMY DINOSAUR"
},
{
"title": "ANACONDA CONFESSIONS"
}
]
}
]
}
FOR XML AUTO, ELEMENTS像以前一样,我们可能决定不产生属性,而是产生元素(仅在XML中):
-- SQL Server
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR XML AUTO, ELEMENTS;
-- Standard SQL
SELECT xmlagg(e)
FROM (
SELECT xmlelement(
NAME a,
xmlelement(
NAME first_name,
first_name
),
xmlelement(
NAME last_name,
last_name
),
xmlagg(xmlelement(
NAME f,
xmlelement(
NAME title,
title
)
))
) e
FROM (
SELECT a.first_name, a.last_name, f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
) t
GROUP BY
first_name,
last_name
) t
除了进行一组XMLELEMENT()
的调用,而不是XMLATTRIBUTES()
的调用之外,没有什么变化。这产生了
<a>
<first_name>NICK</first_name>
<last_name>WAHLBERG</last_name>
<f>
<title>SMILE EARRING</title>
</f>
<f>
<title>WARDROBE PHANTOM</title>
</f>
</a>
<a>
<first_name>PENELOPE</first_name>
<last_name>GUINESS</last_name>
<f>
<title>ACADEMY DINOSAUR</title>
</f>
<f>
<title>ANACONDA CONFESSIONS</title>
</f>
</a>
FOR XML/JSON PATH PATH
策略是我个人最喜欢的。它被用来更明确地创建嵌套的XML或JSON路径结构,并且在将投影分组时还允许额外的嵌套级别。这一点最好通过例子来说明。注意,我现在是如何为我的列使用别名的,而且别名看起来像一个使用'/'
(斜线)的XPath表达式:
-- SQL Server
SELECT
a.first_name AS [author/first_name],
a.last_name AS [author/last_name],
f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR XML PATH;
-- Standard SQL
SELECT xmlagg(xmlelement(
NAME row,
xmlelement(
NAME author,
xmlelement(
NAME first_name,
"author/first_name"
),
xmlelement(
NAME last_name,
"author/last_name"
)
),
xmlelement(
NAME title,
title
)
))
FROM (
SELECT
a.first_name AS "author/first_name",
a.last_name AS "author/last_name",
f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
) t
检查一下,根据惯例,我们现在为作者相关的列在row/author
元素下得到了一个额外的嵌套层次:
<row>
<author>
<first_name>NICK</first_name>
<last_name>WAHLBERG</last_name>
</author>
<title>SMILE EARRING</title>
</row>
<row>
<author>
<first_name>NICK</first_name>
<last_name>WAHLBERG</last_name>
</author>
<title>WARDROBE PHANTOM</title>
</row>
<row>
<author>
<first_name>PENELOPE</first_name>
<last_name>GUINESS</last_name>
</author>
<title>ACADEMY DINOSAUR</title>
</row>
<row>
<author>
<first_name>PENELOPE</first_name>
<last_name>GUINESS</last_name>
</author>
<title>ANACONDA CONFESSIONS</title>
</row>
这真的很整洁!对于这种常见的使用情况,SQL Server的语法肯定要方便得多。 让我们再次尝试用JSON做同样的事情。我们唯一改变的是我们现在使用JSON-path-ish语法,使用点('.'
)而不是斜杠('/'
):
-- SQL Server
SELECT
a.first_name AS [author.first_name],
a.last_name AS [author.last_name],
f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
FOR JSON PATH;
-- Standard SQL
SELECT JSON_ARRAYAGG(JSON_OBJECT(
KEY 'author' VALUE JSON_OBJECT(
KEY 'first_name' VALUE author.first_name,
KEY 'last_name' VALUE author.last_name
),
KEY 'TITLE' VALUE title
ABSENT ON NULL
))
FROM (
SELECT
a.first_name AS "author.first_name",
a.last_name AS "author.last_name",
f.title
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
ORDER BY 1, 2, 3
) t
结果是(同样是嵌套对象):
[
{
"author": {
"first_name": "NICK",
"last_name": "WAHLBERG"
},
"title": "SMILE EARRING"
},
{
"author": {
"first_name": "NICK",
"last_name": "WAHLBERG"
},
"title": "WARDROBE PHANTOM"
},
{
"author": {
"first_name": "PENELOPE",
"last_name": "GUINESS"
},
"title": "ACADEMY DINOSAUR"
},
{
"author": {
"first_name": "PENELOPE",
"last_name": "GUINESS"
},
"title": "ANACONDA CONFESSIONS"
}
]
对于更复杂的嵌套,包括集合的嵌套,在SQL Server中需要一个相关的子查询,同样使用FOR XML
或FOR JSON
语法。
结论
XML和JSON是数据库外部和内部的流行文档格式。在大多数情况下,SQL Server有一些最方便的语法,而标准SQL支持更基本的,因此也更强大的结构。在标准SQL中,几乎任何种类的XML或JSON投影都是可能的,而且通过XMLTABLE()
和JSON_TABLE()
,这些文档也可以被转换回SQL表。在许多应用中,使用这些XML或JSON功能会导致更少的模板代码,因为许多应用不需要数据库和一些客户端之间的中间件,只需要在不同格式之间转换数据。 大多数ORM由于各种原因没有暴露这个功能,主要的原因是魔鬼在细节中。虽然XML和JSON都有很好的标准化,但实现方式差别很大。
- SQL/XML标准主要由DB2、Oracle和PostgreSQL实现。许多方言都提供了一些XML功能,但没有像标准和前三者那样令人印象深刻。SQL Server有
FOR XML
,它对标准的XML序列化非常强大,但对于边缘情况可能有点难以使用 - SQL/JSON标准添加得很晚,而且DB2和Oracle又在很大程度上实现了它,但MariaDB和MySQL也在不断地实现它。PostgreSQL(以及随之而来的兼容方言,如CockroachDB)有他们自己的专有函数和API,这与标准不兼容。再有,SQL Server有
FOR JSON
,对于标准的序列化来说效果很好,但对于边缘情况来说就有点不理想了
由于存在许多细微的差异,这些技术在客户中的采用率很低。jOOQ多年来一直在平整这些细微的差异,而没有隐藏核心功能。SQL/XML和SQL/JSON是jOOQ 3.14(将于2020年第二季度发布)的完美用例,它现在允许在jOOQ专业版和企业版中使用标准的SQL/XML和SQL/JSON语法,以及SQL ServerFOR XML
和FOR JSON
语法。在jOOQ 3.14发布之前,你已经可以在我们的网站上使用当前功能: https://www.jooq.org/translate