目录
开始
先决条件
下载 PartiQL CLI
运行 PartiQL CLI
窗户
macOS (Mac) 和 Unix
命令行教程
介绍
PartiQL 查询与 SQL 兼容
PartiQL 数据模型:许多底层数据存储格式的抽象
了解更多信息
查询嵌套数据
嵌套集合
取消嵌套嵌套集合
了解更多信息
使用 取消嵌套嵌套集合JOIN
使用 LEFT JOIN 取消嵌套数据始终保留父信息
用例:检查嵌套集合是否满足条件
用例:聚合嵌套集合的子查询
嵌套元组值和多步骤路径
取消嵌套任意形式的嵌套集合
用例:取消嵌套标量数组
用例:取消嵌套数组的数组
文字
查询异构和无模式数据
缺少属性的元组
访问和处理缺失属性:缺失值
评估缺少的功能和条件
在结果元组中传播缺失
变量的范围可以超过不同类型的数据
按顺序访问数组元素
[]
多步骤路径
查找数组中每个元素的索引
旋转和取消旋转
取消枢轴元组
旋转到元组
用例:旋转子查询
创建嵌套和非 SQL 结果
使用查询创建嵌套结果SELECT VALUE
创建嵌套结果GROUP BY ... GROUP AS
了解有关 PartiQL 的更多信息
开始
PartiQL 提供了一个交互式 shell,允许用户编写和评估 PartiQL 查询。
先决条件
PartiQL 要求在您的计算机上安装 Java 运行时 (JVM)。 您可以从以下任一位置获取最新版本的 Java 运行时
-
OpenJDK或适用于Windows的OpenJDK
-
神谕
按照有关如何设置到 Java 运行时安装路径的说明进行操作。JAVA_HOME
下载 PartiQL CLI
每个版本的 PartiQL 都附带一个存档,其中包含 PartiQL CLI 作为 压缩文件。
-
下载。 您可能需要单击才能查看zip和tgz存档。 最新的 zip 存档到您的计算机。
Assets``partiql-cli
-
展开(解压缩)计算机上的存档。展开存档将生成以下文件夹结构:
该文件会将 PartiQL 的发布版本附加到存档中,即 .partiql-cli-0.1.0.zip
├── partiql-cli ├── bin │ ├── partiql │ └── partiql.bat ├── lib │ └── ... ├── README.md └── Tutorial ├── code │ └── ... ├── tutorial.html └── tutorial.pdf
其中表示省略的文件/目录。...
根文件夹包含一个文件和 3 个子文件夹partiql-cli``README.md
-
该文件夹包含适用于 macOS 的启动脚本和 Unix 系统和 Windows 系统。执行这些文件 以启动 REPL。
bin``partiql``partiql.bat
-
该文件夹包含运行 PartiQL 所需的所有必需的 Java 库。
lib
-
该文件夹包含教程和表单。子文件夹包含 3 种类型的文件:
Tutorial
pdf
html
code
-
扩展名为 的数据文件 .这些文件包含 PartiQL 我们可以查询的数据。
.env
-
扩展名为 的 PartiQL 查询文件 .这些文件包含 本教程中使用的 PartiQL 查询。
.sql
-
扩展名为 的示例查询输出文件 .这些文件 包含运行教程查询的示例输出 适当的数据。
.output
-
或者,您可以使用在线 CLI 教程。
-
运行 PartiQL CLI
窗户
运行(双击)。这应该打开一个命令行 提示并启动 PartiQL Shell,其中显示:partiql.bat
Welcome to the PartiQL shell!
macOS (Mac) 和 Unix
-
打开终端并导航到该文件夹。
partiql-cli
-
通过键入并按 Enter 启动 REPL,其中显示:
./bin/partiql
文件夹名称将以 PartiQL 版本作为后缀,即 .partiql-cli-0.1.0
Welcome to the PartiQL shell!
命令行教程
要更深入地了解 PartiQL,请查看 CLI 教程。
介绍
PartiQL 提供跨多个 SQL 兼容的统一查询访问 包含结构化、半结构化和嵌套数据的数据存储。 PartiQL 分离了 从基础数据源和数据格式查询。 它使用户能够在有或没有的情况下与数据进行交互 常规架构。
该实现目前仅支持没有 图式。即将推出架构支持。
本教程旨在教SQL用户SQL的PartiQL扩展。这 教程主要由“操作方法”示例驱动。
对于对完整细节和正式感兴趣的读者 PartiQL 的规范,我们建议使用 2 层 PartiQL 正式 规范:正式规范首先描述 PartiQL 核心,它是一种简短而简洁的函数式编程语言。 然后规范通过语法糖层 SQL 兼容性 展示了如何将SQL功能转换为语义等效的 核心 PartiQL 表达式。这些翻译以句法糖的形式呈现 启用 SQL 兼容性。
PartiQL 查询与 SQL 兼容
PartiQL 向后兼容 SQL-92。我们将看到什么 兼容性是指当它用于查询在数据格式中找到的数据时 和数据存储。
SQL-92
对于初学者,给定表格hr.employees
Id name title -------------- ------------- ---------------- 3 Bob Smith null 4 Susan Smith Dev Mgr 6 Jane Smith Software Eng 2
以下 SQL 查询
SELECT e.id, e.name AS employeeName, e.title AS title FROM hr.employees e WHERE e.title = 'Dev Mgr'
也是一个有效的 PartiQL 查询。正如我们从SQL中知道的那样,当这个查询 在表上运行,它将返回结果hr.employees
Id employeeName title ---- -------------- --------- 4 Susan Smith Dev Mgr
信息
为方便起见,我们在文件夹中提供了该文件。您还将在同一文件夹中找到单独的文件 对于教程中的每个查询。
tutorial-all-data.env``Tutorial/code/``.env
例如,跑步
./bin/partiql -e .wiki/assets/code/tutorial-all-data.env将在 REPL 中加载本教程中使用的所有数据。这将 允许您将教程中的查询复制粘贴到 REPL 中并尝试 他们出来了。
PartiQL 数据模型:许多底层数据存储格式的抽象
PartiQL 不仅对 SQL 表进行操作,还对数据进行操作 可能具有嵌套、联合类型、不同的属性 不同的元组,以及我们在今天的 嵌套和/或半结构化格式,如 JSON、Ion、Parquet 等。
为了捕获这种通用性,PartiQL 基于逻辑类型系统: PartiQL 数据模型。每个 PartiQL 实现映射数据格式, 像 JSON、Parquet 等一样,放入遵循 PartiQL 的 PartiQL 数据集中 数据模型。PartiQL 查询处理 PartiQL 数据集抽象。
例如,该表在 PartiQL 数据中表示 建模为此数据集hr.employees
{ 'hr': { 'employees': << -- a tuple is denoted by { ... } in the PartiQL data model { 'id': 3, 'name': 'Bob Smith', 'title': null }, { 'id': 4, 'name': 'Susan Smith', 'title': 'Dev Mgr' }, { 'id': 6, 'name': 'Jane Smith', 'title': 'Software Eng 2'} >> } }
请注意,嵌套在 中。 分隔符... 表示数据 是一个无序集合(也称为 bag),情况就是如此 与 SQL 表。也就是说,三个元组之间没有顺序。 单行注释以行尾开头,结束于行尾。employees``hr``<<``>>``--
一种非常不同类型的数据源可能会导致相同的 PartiQL 数据。例如,一组包含以下内容的 JSON 文件 JSON 对象
{ "hr" : { "employees": [ { "id": 3, "name": "Bob Smith", "title": null }, { "id": 4, "name": "Susan Smith", "title": "Dev Mgr" }, { "id": 6, "name": "Jane Smith", "title": "Software Eng 2"} ] } }
可能会被支持 PartiQL 的 实现到与表相同的 PartiQL 抽象中。hr.employees
附加到的 JSON 值是一个有序列表。PartiQL 实现可以提供自己的映射,来自流行的 数据格式,例如CSV,TSV,JSON,Ion等,到PartiQL数据模型和/或允许客户端 以实现自己的映射。employee
备注:你会不断注意到PartiQL的相似性 表示法和 JSON 表示法。还要注意细微的差异: 在 SQL兼容性的兴趣,PartiQL文字是单引号,而 JSON 文本是双引号的。
备注:您可能从概念上认为反序列化程序输入 JSON 并输出 PartiQL 数据集。但不要假设查询 PartiQL 实现的处理必须实际解析和 将底层数据存储的每一比特抽象为 PartiQL。
回到我们的查询
SELECT e.id, e.name AS employeeName, e.title AS title FROM hr.employees e WHERE e.title = 'Dev Mgr'
在 PartiQL 中计算查询将生成:
<< { 'id': 4, 'employeeName': 'Susan Smith', 'title': 'Dev Mgr' } >> --- OK!
结果保持不变,无论是否 SQL 表或 JSON 文件。所需要的只是一个 名称与 PartiQL 抽象之间的关联 数据。hr.employees``hr.employees
本着同样的精神,相同的PartiQL抽象可能来自CSV。 文件或镶木地板文件,这种格式获得了很大的吸引力,这要归功于 存储数据的有效方式。同样,相同的查询使 完美的感觉,无论背后的存储格式到底是什么。hr.employees
了解更多信息
-
PartiQL 数据集看起来非常像 JSON。
有什么区别?事实上,PartiQL 采用了元组/对象和数组 JSON 的表示法。但是,PartiQL 字符串文本表示 用单引号。重要的是,PartiQL 的标量类型是那些 SQL,而不仅仅是字符串,数字和布尔值,如JSON。
-
实现是否需要具有目录?
如果查询引用 名称,目录在逻辑上验证名称是否存在。 但是,我们还将看到不引用名称的 PartiQL 查询。
查询嵌套数据
SQL-92 仅具有具有包含标量值的元组的表。一把钥匙 许多现代格式的特征是嵌套数据。也就是说,属性 值本身可以是表(即元组的集合),也可以是 标量数组,或数组数组和许多其他组合。让我们 仔细看看 PartiQL 的功能(SQL 扩展),这些功能允许我们 以使用嵌套数据。
我们还包括标题为“用例”的部分。此类“用例”部分不会 引入其他功能。他们只是展示了如何结合 一些具有标准SQL功能的新颖PartiQL功能,以便 解决大量问题。
嵌套集合
现在让我们将嵌套属性添加到数据集中。projects
{ 'hr': { 'employeesNest': << { 'id': 3, 'name': 'Bob Smith', 'title': null, 'projects': [ { 'name': 'AWS Redshift Spectrum querying' }, { 'name': 'AWS Redshift security' }, { 'name': 'AWS Aurora security' } ] }, { 'id': 4, 'name': 'Susan Smith', 'title': 'Dev Mgr', 'projects': [] }, { 'id': 6, 'name': 'Jane Smith', 'title': 'Software Eng 2', 'projects': [ { 'name': 'AWS Redshift security' } ] } >> } }
请注意,的值是一个数组。数组用逗号分隔的数组元素表示。在我们的示例中,数组 恰好是一个元组数组。我们将看到数组可能是数组 任何东西,而不仅仅是元组数组。'projects'``[ ... ]
取消嵌套嵌套集合
以下查询查找处理包含以下内容的项目的员工的姓名 字符串并输出它们以及项目名称。请注意,查询只有一个扩展名 超过标准 SQL ---部分。'security'``'security'``e.projects AS p
SELECT e.name AS employeeName, p.name AS projectName FROM hr.employeesNest AS e, e.projects AS p WHERE p.name LIKE '%security%'
我们查询的输出是
<< { 'employeeName': 'Bob Smith', 'projectName': 'AWS Redshift security' }, { 'employeeName': 'Bob Smith', 'projectName': 'AWS Aurora security' }, { 'employeeName': 'Jane Smith', 'projectName': 'AWS Redshift security' } >> --- OK!
SQL 的扩展是子句项。 标准 SQL 会尝试查找以表命名的架构,由于在我们的示例中没有表,因此查询将失败。相反,PartiQL 识别为引用 的属性。FROM``e.projects AS p``e``projects``e.projects``e.projects``projects``e
一旦我们允许这个扩展,语义就是类似的SQL。别名 (在 PartiQL 中也称为变量)绑定到每个员工,在 转。对于每个员工,变量绑定到每个 反过来,员工的项目。因此,查询的含义,如 SQL, 是e``p
Foreach 员工元组来自 Foreach 项目元组来自 if 输出
e``hr.employeesNest``p``e.projects``p.name LIKE '%security%'``e.name AS employeeName, p.name AS projectName
请注意,我们的查询涉及的变量范围超过嵌套 集合(在示例中),以及 范围超过表(在示例中),就像标准 SQL 别名一样。 所有变量,无论它们的范围如何,都可以在任何地方使用 我们将在下面的示例中看到的 、 子句。p``e``FROM``WHERE``SELECT
了解更多信息
-
我只能取消嵌套元组数组吗?
不,任何东西都可以取消嵌套。 例如,标量数组等。
-
e.projects AS p
是否必须出现在相同的FROM
子句中 这定义了E
?不。例如,请参阅下面的用例 涉及子查询。在那里,和在 单独的条款。
e``p``FROM
-
如何强制
e.projects
引用嵌套属性项目,即使有一个名为e
的架构和表项目
?``使用语法 。回想一下,在 缺少 ,为了 SQL 兼容性,PartiQL 将首先尝试取消引用 目录。
@e.projects``@``e.projects
-
SQL允许我在编写时避免编写显式别名
e
, 说,e.name
。我也可以避免在 PartiQL 中写e
吗?SQL允许我们避免在模式 这些表允许正确的取消引用。PartiQL 也这样做。 但是,回想一下,PartiQL 数据集不需要架构。 事实上,我们的示例没有假设模式。缺席的情况下 在架构中,不能省略别名(变量)。例如 如果你只写,没有模式,PartiQL 不能 告诉您是指员工姓名还是项目名称。因此,您需要 显式写入别名(变量)。
name
此规则有一个例外:如果您的查询包含单个项目 在其子句中,可以省略别名(变量)。例如,你 可以写
FROM
SELECT name FROM hr.employeesNest
在这种情况下,很明显可能只是员工 名称,因此 PartiQL 允许您不提供别名(变量)。
name
不过,为清楚起见,我们建议您始终使用别名 (变量),这就是本教程的作用。
-
如果有模式,我可以避免写入别名
p
吗?不。必须编写以表示迭代 项目。
p
使用 取消嵌套嵌套集合JOIN
在本节中,我们只是介绍另一种表达和思考的方式 关于取消嵌套集合。
有人可能会认为 从某种意义上说,示例在员工和项目之间执行 A。 如果它可以帮助您从 的角度思考,您可以替换逗号 跟。也就是说,以下两个查询是等效的。FROM``JOIN``JOIN``JOIN
+-----------------------------------+-----------------------------------------+ | SELECT e.name AS employeeName, | SELECT e.name AS employeeName, | | p.name AS projectName | p.name AS projectName | | FROM hr.employeesNest AS e, | FROM hr.employeesNest AS e CROSS JOIN | | e.projects AS p | e.projects AS p | | WHERE p.name LIKE '%security%' | WHERE p.name LIKE '%security%' | +-----------------------------------+-----------------------------------------+
使用 LEFT JOIN 取消嵌套数据始终保留父信息
假设我们要编写一个查询,该查询以一袋 从 中元组整个员工和项目信息。我们想要的查询结果是这袋元组 带有属性、 和 :hr.employeesNest``id``employeeName``title``projectName
<< { 'id': 3, 'employeeName': 'Bob Smith', 'title': NULL, 'projectName': 'AWS Redshift Spectrum querying' }, { 'id': 3, 'employeeName': 'Bob Smith', 'title': NULL, 'projectName': 'AWS Redshift security' }, { 'id': 3, 'employeeName': 'Bob Smith', 'title': NULL, 'projectName': 'AWS Aurora security' }, { 'id': 4, 'employeeName': 'Susan Smith', 'title': 'Dev Mgr' }, { 'id': 6, 'employeeName': 'Jane Smith', 'title': 'Software Eng 2', 'projectName': 'AWS Redshift security' } >> --- OK!
请注意,结果中有一个元组,尽管 事实上,苏珊没有项目。苏珊的。 我们可以通过使用运算符将员工和项目组合在一起来获得此结果,如下所示:'Susan Smith'``projectName``null``LEFT JOIN
SELECT e.id AS id, e.name AS employeeName, e.title AS title, p.name AS projectName FROM hr.employeesNest AS e LEFT JOIN e.projects AS p ON true
此查询的语义可以认为是
foreach employee tuple `e` from `hr.employeesNest` if the `e.projects` is an empty collection then *// this part is special about LEFT JOINs* output `e.id AS id`, `e.name AS employeeName`, `e.title AS title` and output a `null AS projectName` else *// the following part is identical to plain (inner) JOINs* foreach project tuple `p` from `e.projects` output `e.id AS id`, `e.name AS employeeName`, `e.title AS title`
用例:检查嵌套集合是否满足条件
以下用例使用了我们所拥有的非嵌套功能 已经在新的用例中讨论过。出现的一个教训是,我们 可以使用范围超过嵌套数据的变量(SQL 别名),就好像它们是 标准 SQL 别名。这种认识给了我们解决的能力 仅通过组合非嵌套功能即可获得大量用例 具有我们已经从标准SQL中了解的功能。
在我们的第一个用例中,我们想要一个返回 参与包含单词的项目的员工。该解决方案采用 SQL 的“(子查询)” 功能,以及取消嵌套:'security'``EXISTS
SELECT e.name AS employeeName FROM hr.employeesNest AS e WHERE EXISTS ( SELECT * FROM e.projects AS p WHERE p.name LIKE '%security%')
返回
<< { 'employeeName': 'Bob Smith' }, { 'employeeName': 'Jane Smith' } >> --- OK!
在第二个用例中,我们想要一个输出 拥有多个安全项目的员工,以及 我们知道员工的键(例如,属性 保证每个员工都有唯一的价值)。 我们可以通过使用 和 的组合来找到所需的员工。在我们的示例中,假设该属性是雇员的主键。然后我们可以找到 具有多个安全项目的员工具有以下查询:GROUP BY``HAVING``id
我们也可以将运算符与子查询的结果一起使用,但是当前实现的问题阻止了我们这样做。>
SELECT e.name AS employeeName FROM hr.employeesNest e, e.projects AS p WHERE p.name LIKE '%security%' GROUP BY e.id, e.name HAVING COUNT(*) > 1
返回
<< { 'employeeName': 'Bob Smith' } >> --- OK!
用例:聚合嵌套集合的子查询
接下来,让我们找出有多少个查询项目(即其 名称包含“查询”一词)每个员工都有。
做出和以前一样的假设,这是员工的关键,我们可以解决 查询的问题id
SELECT e.name AS employeeName, COUNT(p.name) AS queryProjectsNum FROM hr.employeesNest e LEFT JOIN e.projects AS p ON p.name LIKE '%querying%' GROUP BY e.id, e.name
返回
<< { 'employeeName': 'Bob Smith', 'queryProjectsNum': 1 }, { 'employeeName': 'Susan Smith', 'queryProjectsNum': 0 }, { 'employeeName': 'Jane Smith', 'queryProjectsNum': 0 } >> --- OK!
请注意,此查询的结果包括 Susan Smith 和 Jane Smith,他们没有 查询项目。
嵌套元组值和多步骤路径
值也可以是元组 - 在许多中也称为对象和结构 模型和格式。例如,以下项目中的项目值 元组始终是具有项目名称和项目组织的元组。
{ 'hr': { 'employeesWithTuples': << { 'id': 3, 'name': 'Bob Smith', 'title': null, 'project': { 'name': 'AWS Redshift Spectrum querying', 'org': 'AWS' } }, { 'id': 6, 'name': 'Jane Smith', 'title': 'Software Eng 2', 'project': { 'name': 'AWS Redshift security', 'org': 'AWS' } } >> } }
PartiQL 的多步骤路径支持在元组内导航。例如 以下查询查找 AWS 项目并输出项目名称和 员工姓名。
SELECT e.name AS employeeName, e.project.name AS projectName FROM hr.employeesWithTuples e WHERE e.project.org = 'AWS'
结果是
<< { 'employeeName': 'Bob Smith', 'projectName': 'AWS Redshift Spectrum querying' }, { 'employeeName': 'Jane Smith', 'projectName': 'AWS Redshift security' } >> --- OK!
取消嵌套任意形式的嵌套集合
前面的示例显示了嵌套属性,这些属性是数组 元组。嵌套属性不一定是 元组的集合。它们也可能只是标量数组, 数组的数组,或数据的任意组合 可以通过组合标量、元组和数组来创建。你不需要学习 每种情况都有不同的查询语言功能集。解嵌套 我们已经看到的功能就足够了。
用例:取消嵌套标量数组
与每个员工关联的项目列表可能只是项目名称的列表 字符串。用普通字符串替换嵌套元组给了我们hr.employeesNest
{ 'hr': { 'employeesNestScalars': << { 'id': 3, 'name': 'Bob Smith', 'title': null, 'projects': [ 'AWS Redshift Spectrum querying', 'AWS Redshift security', 'AWS Aurora security' ] }, { 'id': 4, 'name': 'Susan Smith', 'title': 'Dev Mgr', 'projects': [] }, { 'id': 6, 'name': 'Jane Smith', 'title': 'Software Eng 2', 'projects': [ 'AWS Redshift security' ] } >> } }
让我们在修订后的员工数据上重复前面的用例。
以下查询查找从事项目的员工的姓名 包含字符串并将它们与名称一起输出 的“安全”项目。'security'
SELECT e.name AS employeeName, p AS projectName FROM hr.employeesNestScalars AS e, e.projects AS p WHERE p LIKE '%security%'
前面的查询返回
<< { 'employeeName': 'Bob Smith', 'projectName': 'AWS Redshift security' }, { 'employeeName': 'Bob Smith', 'projectName': 'AWS Aurora security' }, { 'employeeName': 'Jane Smith', 'projectName': 'AWS Redshift security' } >> --- OK!
变量范围(再次)超过 的内容。在 这种情况,由于有字符串(与元组相反),因此 变量每次绑定到项目名称字符串。因此,这 可以将查询视为执行以下代码片段。p``e.projects``e.projects``p
foreach employee tuple `e` from `hr.employeesNestScalars` foreach project `p` from `e.projects` if the string `p` matches `'%security%'` output `e.name AS employeeName` and the string `p AS projectName`
用例:取消嵌套数组的数组
数组也可以直接包含数组,而不干预元组,如 在数据集中。matrices
{ 'matrices': << { 'id': 3, 'matrix': [ [2, 4, 6], [1, 3, 5, 7], [9, 0] ] }, { 'id': 4, 'matrix': [ [5, 8], [ ] ] } >> }
以下查询查找每个偶数并输出偶数 以及发现它的元组。id
SELECT t.id AS id, x AS even FROM matrices AS t, t.matrix AS y, y AS x WHERE x % 2 = 0
前面的查询返回
<< { 'id': 3, 'even': 2 }, { 'id': 3, 'even': 4 }, { 'id': 3, 'even': 6 }, { 'id': 3, 'even': 0 }, { 'id': 4, 'even': 8 } >> --- OK!
非正式地,可以将查询的评估视为
foreach tuple `t` from `matrices` foreach array `y` from `t.matrix` foreach number `x` from `y` if `x` is even then output `t.id AS id` and `x AS even`
文字
PartiQL 查询语言的文本对应于 PartiQL 数据模型:
-
标量,包括遵循 SQL 语法的标量,包括以下 适用。例如:
null
-
5
-
'foo'
-
-
元组,用元组元素表示,由 (也称为结构和/或对象 多种格式和其他数据模型)
{...}``,
-
{ 'id' : 3, 'arr': [1, 2] }
-
-
数组,用数组元素表示
[...]``,
-
[ 1, 'foo' ]
-
-
袋子,用袋子元素表示,由
<< ... >>``,
-
<< 1, 'foo'>>
-
请注意,本着 PartiQL 数据模型的精神,文本组成 自由和任何类型的文字可以出现在任何元组、数组和 袋字面,例如,
{ 'id': 3, 'matrix': [ [2, 4, 6], 'NA' ] }
查询异构和无模式数据
许多格式不需要描述数据的模式,即无模式数据。在这种情况下,可以有各种 数据中的“异质性”:
-
一个元组可能具有属性,而另一个元组可能没有 此属性
x
-
在集合的一个元组中,属性可能是一种类型,例如, 字符串,而在同一集合的另一个元组中相同 属性可以是不同的类型 - 例如,数组。
x``x
-
集合的元素(无论是包还是数组)可以是异构的(没有 相同类型)。例如,第一个元素可能是一个字符串,即 第二个可以是整数,第三个可以是数组。
-
一般来说,任何组合都是可能的,因为我们可以捆绑 阵列和袋中的异构元素。
异构性并非无架构所特有的。架构可能允许 数据类型的异构性。例如,其中一个配置单元 数据类型是联合类型,它允许值属于 类型列表。考虑以下架构,其属性可能是 字符串或字符串数组projects
配置单元联合类型
CREATE TABLE employeesMixed( id: INT, name: STRING, title: STRING, projects: UNIONTYPE<STRING, ARRAY<STRING>> );
遵循此架构的 PartiQL 元组集合可以是
{ 'hr': { 'employeesMixed1': << { 'id': 3, 'name': 'Bob Smith', 'title': null, 'projects': [ 'AWS Redshift Spectrum querying', 'AWS Redshift security', 'AWS Aurora security' ] }, { 'id': 4, 'name': 'Susan Smith', 'title': 'Dev Mgr', 'projects': [] }, { 'id': 6, 'name': 'Jane Smith', 'title': 'Software Eng 2', 'projects': 'AWS Redshift security' } >> } }
因此,我们看到数据可能具有异质性---无论是否 它们是否由架构描述。PartiQL 解决异构问题 数据,我们将在下一个用例和功能中看到 介绍。
缺少属性的元组
让我们回到桌子(即元组袋)。 Bob Smith 没有标题,正如 SQL 中的典型情况一样,缺少标题是 使用值建模。hr.employees``null
{ 'hr': { 'employees': << { 'id': 3, 'name': 'Bob Smith', 'title': null } { 'id': 4, 'name': 'Susan Smith', 'title': 'Dev Mgr' } { 'id': 6, 'name': 'Jane Smith', 'title': 'Software Eng 2'} >> } }
如今,许多半结构化格式允许用户表示 以两种方式“丢失”信息。
-
第一种方法是使用 .
null
-
第二种是属性的明显缺失 元。
也就是说,我们可以表示鲍勃·史密斯没有头衔的事实 只需在元组中没有属性:title``'Bob Smith'
{ 'hr': { 'employeesWithMissing': << { 'id': 3, 'name': 'Bob Smith' }, -- no title in this tuple { 'id': 4, 'name': 'Susan Smith', 'title': 'Dev Mgr' }, { 'id': 6, 'name': 'Jane Smith', 'title': 'Software Eng 2'} >> } }
PartiQL 不争论何时使用 s 以及何时使用 “失踪”。无数数据集已经使用两者之一或两者之一。 但是,PartiQL 使查询能够区分 null 和 缺失值,并且还启用具有 null 和 缺失值。事实上,PartiQL 使得传播源代码变得非常容易。 数据空作为查询结果空和源数据缺少属性进入 结果缺少属性。null
访问和处理缺失属性:缺失值
再次考虑这个PartiQL查询,它恰好也是一个SQL 查询。
SELECT e.id, e.name AS employeeName, e.title AS title FROM hr.employeesWithMissing AS e WHERE e.title = 'Dev Mgr'
当查询经过鲍勃·史密斯元组时会发生什么,该元组具有 不?title
回答这个问题的第一步是了解 别名(变量)绑定到元组时的路径。用更基本的术语来说,什么是 表达式的结果 ? PartiQL说这是特殊价值。 行为与 非常相似。e.title``e``{ 'id': 3, 'name': 'Bob Smith' }``{ 'id': 3, 'name': 'Bob Smith' }.title``MISSING``MISSING``null
评估缺少的功能和条件
如果一个函数(包括中缀函数,如 )输入一个函数的结果是 。在本例中, 这意味着该条款将评估 当绑定到 和 时,像在 SQL 中一样,当它不绑定时,子句失败 评估为 。因此,输出将是=``MISSING``NULL``WHERE``e.title='Dev Mgr'``NULL``e``{ 'id': 3, 'name': 'Bob Smith' }``WHERE``true
<< { 'id': 4, 'employeeName': 'Susan Smith', 'title': 'Dev Mgr' } >> --- OK!
在结果元组中传播缺失
如果缺少属性,或者更一般地说,如果缺少属性,会发生什么情况 返回表达式出现在 ?MISSING``SELECT
SELECT e.id, e.name AS employeeName, e.title AS outputTitle FROM hr.employeesWithMissing AS e
查询将为每个员工输出一个元组。当它输出 鲍勃·史密斯元组,将评估到然后 输出元组将没有属性。e.title``NULL``outputTitle
<< { 'id': 3, 'employeeName': 'Bob Smith' }, { 'id': 4, 'employeeName': 'Susan Smith', 'outputTitle': 'Dev Mgr' }, { 'id': 6, 'employeeName': 'Jane Smith', 'outputTitle': 'Software Eng 2' } >> --- OK!
同样的处理也会发生,比如说,如果我们有这个 将标题转换为大写字母的查询:MISSING
SELECT e.id, e.name AS employeeName, UPPER(e.title) AS outputTitle FROM hr.employeesWithMissing AS e
同样,将计算为 for ,然后 是 并且还评估为 。 因此,结果将是:e.title``MISSING``'Bob Smith'``UPPER(e.title)``UPPER(MISSING)``NULL
<< { 'id': 3, 'employeeName': 'Bob Smith', 'outputTitle': NULL }, { 'id': 4, 'employeeName': 'Susan Smith', 'outputTitle': 'DEV MGR' }, { 'id': 6, 'employeeName': 'Jane Smith', 'outputTitle': 'SOFTWARE ENG 2' } >> --- OK!
变量的范围可以超过不同类型的数据
PartiQL 变量(在 SQL 中称为别名)可以绑定到 查询计算期间的不同类型。这与 SQL 不同,其中 变量始终绑定到元组。它甚至与什么不同 发生在用例中:取消嵌套标量数组和 在用例:取消嵌套数组数组中发生了什么。
在第一个用例中,PartiQL 变量碰巧总是绑定到一个字符串(给定 示例)。在第二个用例中,PartiQL 变量是 始终绑定到数组(同样,给定 示例)。p``y
要说明绑定到不同类型的变量,请考虑 数据集中的以下扭曲。一些 数组的元素是纯字符串,有些是 元组。即使是员工元组也并不总是具有相同的属性。employeesNest``projects
{ 'hr': { 'employeesMixed2': << { 'id': 3, 'name': 'Bob Smith', 'title': null, 'projects': [ { 'name': 'AWS Redshift Spectrum querying' }, 'AWS Redshift security', { 'name': 'AWS Aurora security' } ] }, { 'id': 4, 'name': 'Susan Smith', 'title': 'Dev Mgr', 'projects': [] }, { 'id': 6, 'name': 'Jane Smith', 'projects': [ 'AWS Redshift security'] } >> } }
此查询生成员工姓名 -- 员工 项目对。hr.employeesMixed2
SELECT e.name AS employeeName, CASE WHEN (p IS TUPLE) THEN p.name ELSE p END AS projectName FROM hr.employeesMixed2 AS e, e.projects AS p
请注意子表达式 。可以使用运算符 以在评估时根据其类型检查值。 另请注意,变量绑定到不同的类型。(p IS TUPLE)``IS``p
通常,查询的子句绑定其变量(别名) 到数据。变量不需要绑定到具有相同数据 类型。每个绑定都馈送到子句,子句评估其 表达 式。FROM``SELECT
此表显示了子句生成的每个变量的绑定 以及子句的相应元组输出。FROM``SELECT
+-----------------------+-----------------------+-----------------------+ | Variable `e` | Variable `p` | Result tuple | +=======================+=======================+=======================+ | { 'id': 3, | { 'name': 'AWS | { | | | Redshift Spectrum | | | 'name': 'Bob Smith', | querying' } | 'employeeName': 'Bob | | | | Smith', | | 'title': null, | | | | | | 'projectName': 'AWS | | 'projects': [ { | | Redshift Spectrum | | 'name': 'AWS Redshift | | querying' | | Spectrum querying' }, | | | | | | } | | 'AWS Redshift | | | | security', | | | | | | | | { 'name': 'AWS Aurora | | | | security' } | | | | | | | | ] | | | | | | | | } | | | +-----------------------+-----------------------+-----------------------+ | { 'id': 3, | 'AWS Redshift | { | | | security' | | | 'name': 'Bob Smith', | | 'employeeName': 'Bob | | | | Smith', | | 'title': null, | | | | | | 'projectName': 'AWS | | 'projects': [ { | | Redshift security' | | 'name': 'AWS Redshift | | | | Spectrum querying' }, | | } | | | | | | 'AWS Redshift | | | | security', | | | | | | | | { 'name': 'AWS Aurora | | | | security' } | | | | | | | | ] | | | | | | | | } | | | +-----------------------+-----------------------+-----------------------+ | { 'id': 3, | { 'name': 'AWS Aurora | { | | | security' } | | | 'name': 'Bob Smith', | | 'employeeName': 'Bob | | | | Smith', | | 'title': null, | | | | | | 'projectName': 'AWS | | 'projects': \[ { | | Aurora security' | | 'name': 'AWS Redshift | | | | Spectrum querying' }, | | } | | | | | | 'AWS Redshift | | | | security', | | | | | | | | { 'name': 'AWS Aurora | | | | security' } | | | | | | | | \] | | | | | | | | } | | | +-----------------------+-----------------------+-----------------------+ | { 'id': 6, | 'AWS Redshift | { | | | security' | | | 'name': 'Jane Smith', | | 'employeeName': | | | | 'Jane Smith', | | 'projects': \[ 'AWS | | | | Redshift security' \] | | 'projectName': 'AWS | | | | Redshift security' | | } | | | | | | } | +-----------------------+-----------------------+-----------------------+
按顺序访问数组元素
SQL 允许我们使用子句对查询的输出进行排序。但是,SQL 数据模型无法识别 输入数据。相比之下,许多新的数据格式具有数组; 数组的元素有一个顺序。我们可能想找到一个数组元素 通过其索引或,我们可能想要找到某些位置 元素在其数组中。ORDER BY
<Array> [<number>]
让我们再次考虑数据集。hr.employeesNest
{ 'hr': { 'employeesNest': << { 'id': 3, 'name': 'Bob Smith', 'title': null, 'projects': [ { 'name': 'AWS Redshift Spectrum querying' }, { 'name': 'AWS Redshift security' }, { 'name': 'AWS Aurora security' } ] }, { 'id': 4, 'name': 'Susan Smith', 'title': 'Dev Mgr', 'projects': [] }, { 'id': 6, 'name': 'Jane Smith', 'title': 'Software Eng 2', 'projects': [ { 'name': 'AWS Redshift security' } ] } >> } }
该属性是一个元组数组;也就是说,每个元组 有一个与之关联的序数。以下查询返回每个 员工姓名,以及员工的第一个项目。projects
SELECT e.name AS employeeName, e.projects[0].name AS firstProjectName FROM hr.employeesNest AS e
查询返回
<< { 'employeeName': 'Bob Smith', 'firstProjectName': 'AWS Redshift Spectrum querying' }, { 'employeeName': 'Susan Smith' }, { 'employeeName': 'Jane Smith', 'firstProjectName': 'AWS Redshift security' } >> --- OK!
多步骤路径
从技术上讲,该结构是一种路径步骤。 例如,请注意 4 步路径 。当绑定到 的第一个元组时,路径将结果变为数组[<number>]``e.projects[0].name``e``hr.employeesNest``e.projects
[ { 'name': 'AWS Redshift Spectrum querying' }, { 'name': 'AWS Redshift security' }, { 'name': 'AWS Aurora security' } ]
因此,应用步骤(即 评估 ) 导致 。最后,评估步骤(即评估)线索 自。[0]``e.projects``e.projects[0]``{'name': 'AWS Redshift Spectrum querying'}``.name``e.projects[0]``e.projects[0].name``'AWS Redshift Spectrum querying'
查找数组中每个元素的索引
假设每个员工的项目都按优先级顺序排序。 以下查询查找每个员工的姓名 涉及安全项目、安全项目及其索引 数组。projects
SELECT e.name AS employeeName, p.name AS projectName, o AS projectPriority FROM hr.employeesNest AS e, e.projects AS p AT o WHERE p.name LIKE '%security%'
请注意新功能:。虽然范围超过元素 的数组中,变量被赋给索引 数组中的元素。查询返回:AT o``p``e.projects``o
<< { 'employeeName': 'Bob Smith', 'projectName': 'AWS Redshift security', 'projectPriority': 1 }, { 'employeeName': 'Bob Smith', 'projectName': 'AWS Aurora security', 'projectPriority': 2 }, { 'employeeName': 'Jane Smith', 'projectName': 'AWS Redshift security', 'projectPriority': 0 } >> --- OK!
旋转和取消旋转
许多查询需要范围并收集属性名称/值 元组对或映射的键/值对。
取消枢轴元组
考虑这个数据集,它提供了多个收盘价 股票代码。
{ 'closingPrices': << { 'date': '4/1/2019', 'amzn': 1900, 'goog': 1120, 'fb': 180 }, { 'date': '4/2/2019', 'amzn': 1902, 'goog': 1119, 'fb': 183 } >> }
以下查询对股票代码/价格对进行反转。
SELECT c."date" AS "date", sym AS "symbol", price AS price FROM closingPrices AS c, UNPIVOT c AS price AT sym WHERE NOT sym = 'date'
请注意在此查询中使用 。双引号允许我们 消除关键字和标识符的歧义。 双引号还可以指定属性查找区分大小写。"``date``"date"
查询返回
<< { 'date': '4/1/2019', 'symbol': 'amzn', 'price': 1900 }, { 'date': '4/1/2019', 'symbol': 'goog', 'price': 1120 }, { 'date': '4/1/2019', 'symbol': 'fb', 'price': 180 }, { 'date': '4/2/2019', 'symbol': 'amzn', 'price': 1902 }, { 'date': '4/2/2019', 'symbol': 'goog', 'price': 1119 }, { 'date': '4/2/2019', 'symbol': 'fb', 'price': 183 } >> --- OK!
取消透视元组允许使用属性名称,就好像它们是 数据。例如,计算每个的平均价格变得容易 符号为
SELECT sym AS "symbol", AVG(price) AS avgPrice FROM closingPrices c, UNPIVOT c AS price AT sym WHERE NOT sym = 'date' GROUP BY sym
返回
<< { 'symbol': 'amzn', 'avgPrice': 1901 }, { 'symbol': 'fb', 'avgPrice': 181.5 }, { 'symbol': 'goog', 'avgPrice': 1119.5 } >> --- OK!
旋转到元组
旋转将集合转换为元组。例如,考虑 收集
{ 'todaysStockPrices': << { 'symbol': 'amzn', 'price': 1900}, { 'symbol': 'goog', 'price': 1120}, { 'symbol': 'fb', 'price': 180 } >> }
然后进行以下查询PIVOT
PIVOT sp.price AT sp."symbol" FROM todaysStockPrices sp
生成元组
{ 'amzn': 1900, 'goog': 1120, 'fb': 180 } --- OK!
请注意,该查询看起来像一个查询,只是它有一个 .另请注意,查询不会返回元组集合:而是 它从字面上返回一个元组值。PIVOT``SELECT-FROM-WHERE-...``SELECT``PIVOT <value expression> AT <attribute expression>``PIVOT
用例:旋转子查询
(此示例还使用了 PartiQL 的分组功能,创建 嵌套结果与分组依据...组为。
让我们概括一下前面的枢轴情况。我们有一个表格 股价
{ 'stockPrices':<< { 'date': '4/1/2019', 'symbol': 'amzn', 'price': 1900}, { 'date': '4/1/2019', 'symbol': 'goog', 'price': 1120}, { 'date': '4/1/2019', 'symbol': 'fb', 'price': 180 }, { 'date': '4/2/2019', 'symbol': 'amzn', 'price': 1902}, { 'date': '4/2/2019', 'symbol': 'goog', 'price': 1119}, { 'date': '4/2/2019', 'symbol': 'fb', 'price': 183 } >> }
我们希望将其透视为元组集合,其中每个元组 具有日期的所有对,如下所示symbol:price
<< { 'date': date(4/1/2019), 'prices': {'amzn': 1900, 'goog': 1120, 'fb': 180} }, { 'date': date(4/2/2019), 'prices': {'amzn': 1902, 'goog': 1119, 'fb': 183} } >>
以下查询首先为每个日期创建一个组日期价格。 然后,子查询将组枢轴为元组价格。PIVOT
SELECT sp."date" AS "date", (PIVOT dp.sp.price AT dp.sp."symbol" FROM datesPrices as dp ) AS prices FROM StockPrices AS sp GROUP BY sp."date" GROUP AS datesPrices
例如,从 for 返回的集合是datesPrices``GROUP AS``sp.date = date(4/1/2019)
'datesPrices': << { 'sp': { 'date': '4/1/2019', 'symbol': 'amzn', 'price': 1900 } }, { 'sp': { 'date': '4/1/2019', 'symbol': 'goog', 'price': 1120 } }, { 'sp': { 'date': '4/1/2019', 'symbol': 'fb', 'price': 180 } } >>
创建嵌套和非 SQL 结果
PartiQL 允许创建嵌套结果的查询以及查询 产生异构结果。
使用查询创建嵌套结果SELECT VALUE
让我们再次考虑数据集:hr.employeesNestScalars
{ 'hr': { 'employeesNestScalars': << { 'id': 3, 'name': 'Bob Smith', 'title': null, 'projects': [ 'AWS Redshift Spectrum querying', 'AWS Redshift security', 'AWS Aurora security' ] }, { 'id': 4, 'name': 'Susan Smith', 'title': 'Dev Mgr', 'projects': [] }, { 'id': 6, 'name': 'Jane Smith', 'title': 'Software Eng 2', 'projects': [ 'AWS Redshift security' ] } >> } }
以下查询输出 的每个元组, 除了每个元组而不是所有项目只有安全性 员工的项目。这里重要的新功能是 .hr.employeesNestScalars``SELECT VALUE <expression>
SELECT e.id AS id, e.name AS name, e.title AS title, ( SELECT VALUE p FROM e.projects AS p WHERE p LIKE '%security%' ) AS securityProjects FROM hr.employeesNestScalars AS e
结果是
<< { 'id': 3, 'name': 'Bob Smith', 'title': NULL, 'securityProjects': << 'AWS Redshift security', 'AWS Aurora security' >> }, { 'id': 4, 'name': 'Susan Smith', 'title': 'Dev Mgr', 'securityProjects': <<>> }, { 'id': 6, 'name': 'Jane Smith', 'title': 'Software Eng 2', 'securityProjects': << 'AWS Redshift security' >> } >> --- OK!
查询(或子查询,如 示例) 返回计算结果的集合。SELECT VALUE <expression>``<expression>
注意与SQL的区别,它总是产生 元组。如果 SQL 显示为子查询,则 子查询指定是否应强制子查询的结果 进入标量(例如,当 ),强制进入 标量的集合(例如,何时)等。都不是 这适用于 ,它生成一个集合,并且 收集不是强制的。SELECT``SELECT``5 = <subquery>``5 IN <subquery>``SELECT VALUE
创建嵌套结果GROUP BY ... GROUP AS
在 PartiQL 中创建嵌套结果的另一种模式是通过 SQL 的扩展。这种模式更有效,并且 比使用嵌套查询更直观时 所需的嵌套不遵循输入的嵌套。(示例 在 使用 SELECT VALUE 查询创建嵌套结果 是其中之一 输出中的嵌套遵循输入的嵌套,因此, 直观的解决方案不涉及。GROUP AS``GROUP BY``SELECT VALUE``GROUP BY
以下查询输出在中找到的每个安全项目以及员工姓名列表 在项目上工作。hr.employeesNestScalars
SELECT p AS projectName, ( SELECT VALUE v.e.name FROM perProjectGroup AS v ) AS employees FROM hr.employeesNestScalars AS e JOIN e.projects AS p ON p LIKE '%security%' GROUP BY p GROUP AS perProjectGroup
结果是
<< { 'projectName': 'AWS Aurora security', 'employees': << 'Bob Smith' >> }, { 'projectName': 'AWS Redshift security', 'employees': << 'Bob Smith', 'Jane Smith' >> } >> --- OK!
通过使公式化的 SQL 泛化 对查询的 和 子句完全可用的组。与 SQL 的相反,其中 and 子句可以具有聚合函数 分组列,但它们无法访问 分组列。GROUP AS``GROUP BY``SELECT``HAVING``GROUP BY``SELECT``HAVING
为了更好地理解它的工作原理是 最好将 PartiQL 查询视为子句管道,从 的 ,继续 和 结束。每个子句都是一个输入数据和输出数据的函数。 从这个意义上说,这是一个输入的函数 的结果 和 将其结果输出到 .GROUP BY ... GROUP AS``FROM``GROUP BY``SELECT``GROUP BY ... GROUP AS``FROM``SELECT
以下查询(概念上)生成子句的输出。FROM
SELECT e AS e, p AS p FROM hr.employeesNestScalars AS e JOIN e.projects AS p ON p LIKE '%security%'
我们看到,交付的元组集合包括 由该子句输出的员工和项目,即 .这就像SQL的语义。FROM``e``p``FROM``LEFT JOIN``FROM
+-----------------------------------+-----------------------------------+ | Variable `e` | Variable `p` | +===================================+===================================+ | { 'id': 3, | 'AWS Redshift security' | | 'name': 'Bob Smith', | | | 'title': null, | | | 'projects': [ 'AWS Redshift | | | Spectrum querying', | | | 'AWS Redshift security', | | | 'AWS Aurora security' | | | ] | | | } | | +-----------------------------------+-----------------------------------+ | { 'id': 3, | 'AWS Aurora security' | | 'name': 'Bob Smith', | | | 'title': null, | | | 'projects': [ 'AWS Redshift | | | Spectrum querying', | | | 'AWS Redshift security', | | | 'AWS Aurora security' | | | ] | | | } | | +-----------------------------------+-----------------------------------+ | { 'id': 6, | 'AWS Redshift security' | | 'name': 'Jane Smith', | | | 'title': 'Software Eng 2', | | | 'projects': [ 'AWS Redshift | | | security' ] | | | } | | +-----------------------------------+-----------------------------------+
那么可以认为输出 每个分组依据表达式都有一列的表(即,每个 安全项目 ) 和最后一列 值(概念上)是对应于分组依据表达式的员工/项目/元组的集合。因此输出是表GROUP BY ... GROUP AS ...``p``perProjectGroup``e``p``p``GROUP BY ... GROUP AS ...
+-----------------------------------+-----------------------------------+ | `p` | `perProjectGroup` | +===================================+===================================+ | 'AWS Redshift security' | << | | | { e: { 'id': 3, 'name': 'Bob | | | Smith', ... }, p: 'AWS Redshift | | | security' }, | | | | | | { e: { 'id': 6, 'name': 'Jane | | | Smith', ... }, p: 'AWS Redshift | | | security' } | | | >> | +-----------------------------------+-----------------------------------+ | 'AWS Aurora security' | << | | | { e: { 'id': 3, 'name': 'Bob | | | Smith', ...}, p: 'AWS Aurora | | | security' }, | | | >> | +-----------------------------------+-----------------------------------+
最后子句输入上述内容并输出查询 结果。SELECT
了解有关 PartiQL 的更多信息
PartiQL 网站包含新闻、更新、 文档,以及有关 PartiQL 实现的更多信息。
转自:
Tutorial · partiql/partiql-lang-kotlin Wiki (github.com)https://github.com/partiql/partiql-lang-kotlin/wiki/Tutorial