关于 lookml-liquid
这是一份 LookML Liquid 变量和标签的参考技能,面向需要在 Looker 模型中编写动态逻辑的人员。内容说明变量用途、条件判断、用户输入的 SQL 安全处理,以及查询字段状态对逻辑和性能的影响。
主要功能
- 01列出 Liquid 变量及适用位置
- 02区分 _in_query 与 _is_selected
- 03说明用户输入的 SQL 转义
- 04涵盖动态表选择与关联逻辑
- 05提示字段引用的性能影响
适用场景
- 01按查询字段动态选择数据表
- 02依据筛选值生成 SQL 条件
- 03让计算逻辑随所选字段调整
- 04避免链接字段导致额外分组
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ looker-open-source/ looker-skills --skill lookml-liquid安装后在 Claude Code 中输入/lookml-liquid确认已加载。
详细介绍
说明
- 语法:
{{ value }}:输出语法(插入文本)。{% if condition %}:标签语法(逻辑)。
- 常用变量:
value:数据库中的原始值(最适合用于比较)。rendered_value:格式化后的值(最适合用于显示)。_filters['view.field']:用户选择的筛选值。parameter_name._parameter_value:选定的参数值。
- 最佳实践:
- SQL 注入:将用户输入(如
_filters)插入生成字符串字面量的 SQL 时,始终使用| sql_quote。 - 布尔值:如果你的方言要求使用字面量
TRUE/FALSE(如 BigQuery),请在_in_query或_is_selected变量后附加| sql_boolean(例如:{{ view.field._in_query | sql_boolean }})。 - 依赖关系:请记住,
_in_query会检查字段是否用于 SELECT、筛选器和required_fields,而不只是可见列。 - 性能:如果字段尚未在查询中,避免在
link参数中引用{{ field._value }},因为这会迫使 Looker 将该字段添加到GROUP BY子句中,可能导致结果集扇出。如果只需要浏览器结果行中的值,请改用row['view.field']。
- SQL 注入:将用户输入(如
高级变量用法
_in_query 与 _is_selected 的区别
| 变量 | 定义 | 关键区别(汇总) |
|---|---|---|
_in_query | 如果字段位于 SELECT 子句、筛选器或 required_fields 中,则返回 true。 | 如果字段参与了查询,在计算汇总时仍然返回 true。 |
_is_selected | 如果字段位于 SELECT 子句或 required_fields 中,则返回 true。 | 对于维度,在计算汇总(行/列/总计)时返回 false,因为计算汇总时会将维度从查询中移除。 |
警告
如果使用
_is_selected有条件地渲染维度逻辑,该逻辑在汇总行中将失效(返回 false)。如果需要让该逻辑在汇总中保持生效,请使用_in_query;如果希望如此,则需显式处理汇总时的false状态。
Liquid 变量定义
下表介绍了可与 LookML 搭配使用的 Liquid 变量,以及它们的适用位置。
用法键:
- A:
action - DV:
default_value(仪表板) - DE:
description - F:
filters(仪表板元素) - H:
html - LA:标签参数(
label、view_label、group_label、group_item_label) - LI:
link - S:SQL 参数(
sql、sql_on、sql_table_name)
| 变量 | 定义 | 用法 |
|---|---|---|
value | 字段的原始值。 | A、H、LI |
rendered_value | 字段的格式化值。 | A、H、LI |
filterable_value | 为 URL 筛选格式化后的值。 | A、H、LI |
link | 默认的钻取链接 URL。 | A、H、LI、S |
linked_value | 采用默认格式和链接的值。 | A、H、LI |
_filters['view.field'] | 应用于该字段的用户筛选器。 | A、DE、H、LA、LI |
{% date_start filter %} | 日期筛选器的开始日期。 | S |
{% date_end filter %} | 日期筛选器的结束日期。 | S |
{% condition filter %} sql {% endcondition %} | 将筛选逻辑应用于 SQL。 | S |
{% parameter name %} | 参数的值。 | DE、LA、S |
name._parameter_value | 注入参数值(可安全用于逻辑判断)。 | DE、H、LA、LI、S |
_user_attributes['name'] | 用户属性值。 | A、DE、H、LA、LI、S、DV、F |
_model._name | 模型名称。 | A、DE、H、LA、LI、S |
_view._name | 视图名称。 | A、DE、H、LA、LI、S |
_explore._name | Explore 名称。 | A、DE、H、LA、LI、S |
_field._name | 字段名称。 | A、DE、H、LA、LI、S |
view._in_query | 如果查询了该视图中的任意字段,则为 true。 | DE、LA、LI、S |
view.field._in_query | 如果该字段位于查询或筛选器中,则为 true。 | DE、LA、LI、S |
view.field._is_selected | 如果该字段位于 SELECT 中,则为 true。 | DE、LA、LI、S |
view.field._is_filtered | 如果该字段已被筛选,则为 true。 | DE、LA、LI、S |
高级用例
1. 聚合感知(动态表选择)
使用 _in_query,在用户未请求细粒度详情时,将查询路由到较小的预聚合表。这可以显著提升查询性能。
view: orders {
sql_table_name:
{% if orders.created_date._in_query or orders.created_hour._in_query %}
orders_daily_summary -- Fallback to daily partition if granular date used
{% elsif orders.created_month._in_query %}
orders_monthly_summary -- Use monthly summary for high-level queries
{% else %}
orders_all_transactions -- Default/Detail table
{% endif %} ;;
}
2. 动态联接(sql_on)
在联接中使用 _in_query,避免在用户的选择确实需要之前联接大型表。
explore: order_items {
join: users {
type: left_outer
sql_on: ${order_items.user_id} = ${users.id} ;;
relationship: many_to_one
}
join: user_facts {
type: left_outer
sql_on: ${users.id} = ${user_facts.user_id} ;;
relationship: one_to_one
# Only join user_facts if a field from it is actually selected/filtered
sql_where: {% if user_facts._in_query %} 1=1 {% else %} 1=0 {% endif %} ;;
}
}
注:sql_where 技巧是在某些方言中强制移除联接的一种方法;如果支持,使用 {% if %} 的标准 sql_on 逻辑会更简洁。
3. 特定列逻辑(动态分母)
根据查询中是否包含其他字段来更改计算方式。
measure: dynamic_rate {
type: number
sql:
{% if users.traffic_source._is_selected %}
${total_revenue} / NULLIF(${traffic_source_count}, 0)
{% else %}
${total_revenue} / NULLIF(${total_users}, 0)
{% endif %} ;;
}
示例
动态 HTML(条件格式)
dimension: status {
html:
{% if value == 'complete' %}
<span style="color: green">{{ rendered_value }}</span>
{% else %}
<span style="color: red">{{ rendered_value }}</span>
{% endif %} ;;
}
模板化筛选器(派生表)
view: customer_facts {
derived_table: {
sql:
SELECT customer_id, SUM(amount)
FROM orders
WHERE {% condition order_date %} created_at {% endcondition %}
GROUP BY 1 ;;
}
}
复杂逻辑(循环与拆分)
LookML Liquid 可以处理字符串操作和循环,这对于解析复杂的筛选参数或展开值很有用。这种用法并不常见,但在复杂的建模任务中非常实用。
view: brand_category_item {
parameter: filter { type: unquoted }
}
explore: complex_filter_parsing {
# Example: Parsing a string like "Brand1..Category1__Brand2..Category2"
# This logic splits the string by '__' then '..' to generate OR conditions
sql_where:
{% assign items = brand_category_item.filter._parameter_value | split: '__' %}
{% for item in items %}
{% assign parts = item | split: '..' %}
{% if forloop.first %} ( {% else %} OR ( {% endif %}
${products.brand} = '{{ parts[0] }}' AND ${products.category} = '{{ parts[1] }}'
)
{% endfor %}
{% if items.size == 0 %} 1=1 {% endif %}
;;
}
评论
支持 Markdown