本页面面向尝试使用 LookML 在 Looker 中构建探索的所有用户。如果您精通 SQL,尤其是了解内连接和外连接之间的区别,则更容易理解本页内容。如需简要了解内连接和外连接的区别,请参阅 w3schools 上这篇关于 SQL 联接的文章。
Looker 可以成为贵公司的强大 SQL 引擎。借助 LookML 中的抽象建模,数据和 IT 团队可以构建始终为真的通用规则,从而让业务分析师能够构建始终正确的实际查询,即使数据团队从未预料到需要这些查询也是如此。此功能的核心驱动因素是对称汇总算法,它解决了行业中存在的 SQL 联接问题。不过,必须正确执行以下两项操作才能充分利用该算法:包含测量值的每个视图(通常是所有视图)中的主键都必须准确无误,并且每个联接中的 relationship
参数都必须正确无误。
主键
在许多方面,了解表的主键与了解表是什么以及可以对其执行哪些操作本质上是相同的。唯一需要满足的要求是,您选择作为主键的列(或一组串联的列)不得包含重复值。
relationship
参数
现在,您已验证主键,可以确定联接的 relationship
参数的正确值。relationship
参数的用途是告知 Looker 在将联接写入 SQL 查询时是否调用对称汇总。一种可能的方法是告知 Looker 始终调用这些函数,这样就能始终获得准确的结果。不过,这会导致性能下降,因此最好谨慎使用对称汇总。
确定正确值的过程在内部联接和外部联接之间略有不同。
内联接
例如,假设您有一个主键为 order_id
的订单表:
order_id | 金额 | customer_id |
---|---|---|
1 | $25.00 | 1 |
2 | 50.00 美元 | 1 |
3 | 75.00 美元 | 2 |
4 | 35.00 美元 | 3 |
假设您还有一个主键为 customer_id
的客户表:
customer_id | first_name | last_name | 就医情况 |
---|---|---|---|
1 | Amelia | Earhart | 2 |
2 | Bessie | Coleman | 2 |
3 | Wilbur | Wright | 4 |
您可以按 customer_id
字段(这两个表中都存在)联接这两个表。此联接在 LookML 中的表示形式如下所示:
explore: orders { join: customers { type: inner sql_on: ${orders.customer_id} = ${customers.customer_id} ;; relationship: many_to_one } }
此 LookML 联接的结果可以表示为单个联接表,如下所示:
order_id | 金额 | customer_id | customer_id | first_name | last_name | 就医情况 |
---|---|---|---|---|---|---|
1 | $25.00 | 1 | 1 | Amelia | Earhart | 2 |
2 | 50.00 美元 | 1 | 1 | Amelia | Earhart | 2 |
3 | 75.00 美元 | 2 | 2 | Bessie | Coleman | 2 |
4 | 35.00 美元 | 3 | 3 | Wilbur | Wright | 4 |
这里的 many_to_one
关系是指联接字段 (customer_id
) 的一个值在每个表中出现的次数。在 orders
表(左侧表格)中,单个客户 ID 会多次出现(在本例中,这是 ID 为 1
的客户,该客户出现在多行中)。
在 customers
表(右侧表格)中,每个客户 ID 只会出现一次,因为 customer_id
是该表的主键。因此,orders
表中的记录可能会与 customers
表中的单个值有多个匹配项。如果 customers
表中的每一行中的 customer_id
都不唯一,则关系为 many_to_many
。
您可以按照以下步骤通过检查主键以编程方式确定正确的关系值:
- 首先,将
many_to_many
写入为关系。只要主键正确无误,系统便始终会生成准确的结果,因为 Looker 始终会触发对称汇总算法并强制执行准确性。不过,由于该算法会使查询变得复杂并增加运行时间,因此最好尝试将一侧或两侧都更改为one
,而不是many
。 - 查看左侧表中的
sql_on
子句中的字段。如果字段构成了左侧表的主键,您可以将relationship
参数的左侧更改为one
。否则,它通常必须保持many
。(如需了解特殊情况,请参阅本页面后文的注意事项部分。) - 接下来,查看
sql_on
子句中表示右表的字段。如果字段构成了右侧表的主键,您可以将右侧更改为one
。
最佳实践是从左表(等号左侧)和右表(等号右侧)开始编写 sql_on
字词。sql_on
参数中条件的顺序无关紧要,除非该顺序与数据库的 SQL 方言相关。虽然 sql_on
参数不要求您按此方式对字段进行排序,但通过排列 sql_on
条件,使等号的左右两侧与 relationship
参数从左到右的读取方式一致,有助于您确定关系。以这种方式对字段进行排序还有助于您更轻松地一目了然地了解要将新表联接到“探索”中的哪个现有表。
外部联接
对于外部联接,您还需要考虑,在联接期间添加 null 记录时可能会发生扇出。这一点尤为重要,因为 Looker 中的默认联接是左外连接。虽然 null 记录不会影响总和或平均值,但会影响 Looker 运行 type: count
衡量方式。如果执行方式不正确,系统会统计 null 记录(这是不希望的)。
在完全外部联接中,如果联接键缺少另一个表中存在的值,则可以将 null 记录添加到任一表中。下例展示了这一点,其中涉及 orders
表:
order_id | 金额 | customer_id |
---|---|---|
1 | $25.00 | 1 |
2 | 50.00 美元 | 1 |
3 | 75.00 美元 | 2 |
4 | 35.00 美元 | 3 |
例如,假设您还有以下 customers
表:
customer_id | first_name | last_name | 就医情况 |
---|---|---|---|
1 | Amelia | Earhart | 2 |
2 | Bessie | Coleman | 2 |
3 | Wilbur | Wright | 4 |
4 | Charles | Yeager | 3 |
联接这些表后,联接表可以表示为:
order_id | 金额 | customer_id | customer_id | first_name | last_name | 就医情况 |
---|---|---|---|---|---|---|
1 | $25.00 | 1 | 1 | Amelia | Earhart | 2 |
2 | 50.00 美元 | 1 | 1 | Amelia | Earhart | 2 |
3 | 75.00 美元 | 2 | 2 | Bessie | Coleman | 2 |
4 | 35.00 美元 | 3 | 3 | Wilbur | Wright | 4 |
null | null | null | 4 | Charles | Yeager | 3 |
与内连接一样,表的主键之间的关系为 many_to_one
。不过,添加的 null 记录也迫使左侧表格需要对称汇总。因此,您必须将 relationship
参数更改为 many_to_many
,因为执行此联接会破坏左侧表格的计数。
如果本例使用的是左外连接,则不会添加 null 行,并且会丢弃多余的客户记录。在这种情况下,关系仍会是 many_to_one
。这是 Looker 的默认设置,因为系统假定基准表定义了分析。在这种情况下,您要分析的是订单,而不是客户。如果客户表位于左侧,情况会有所不同。
多级联接
在某些探索中,基表会联接到一个或多个视图,而这些视图又需要联接到一个或多个其他视图。在此示例中,这意味着某个表将与“客户”表联接。在这些情况下,评估 relationship
参数时,最好仅查看要写入的单个联接。Looker 会了解下游扇出何时会影响查询,即使受影响的视图不在实际创建扇出的联接中也是如此。
Looker 如何帮助我?
Looker 中提供了一些机制来帮助确保关系值正确无误。其中之一是检查主键是否具有唯一性。每当存在扇出且需要对称汇总来计算衡量指标时,Looker 都会检查所用主键是否唯一。如果不唯一,则在查询运行时会显示错误(不过,不会出现 LookML 验证器错误)。
此外,如果 Looker 无法处理扇出(通常是因为未指明主键),则“探索”视图中不会显示该视图中的任何指标。要解决此问题,只需将某个字段指定为主键,即可让您的指标显示在“探索”中。
需要考虑的事项
对称汇总的方言支持
Looker 可以连接到不支持对称汇总的某些方言。您可以在 symmetric_aggregates
文档页面上查看方言列表及其对对称汇总的支持情况。
特殊情况
本页上文中的 内连接部分指出,若要确定正确的关系值,您应查看左侧表中的 sql_on
子句中的字段:“如果这些字段构成了左侧表的主键,您可以将 relationship
参数的左侧更改为 one
。如果不是,则通常必须保留为 many
。”除非您的表格包含多个列,且这些列中没有重复的记录,否则这一点是正确的。在这种情况下,在构建关系时,您可以将任何此类列视为主键,即使它不是指定为 primary_key: yes
的列也是如此。
为确保上文中的陈述始终对您指定的列保持不变,最好制定某种软件规则。如果是,请继续将其视为此类视图,并在视图文件中记下其特殊属性,以便他人日后参考(附上 SQL Runner 链接以证明这一点)。不过请注意,当某个字段被指定为主键时,Looker 会确认隐式唯一性的真实性,但不会对其他字段执行相同操作。它只会不调用对称汇总算法。