数据与分析
数据准备
原始表很少能单独回答一个问题。数据准备把它们联接起来、把列的类型改对,并把整套配方保存下来,好让明天的数据走完全相同的步骤。
位置在 数据 → 数据目录 → 数据准备。产出是一张新的已准备表,与其他表别无二致:可以作图、可以查询、可以挂到智能体上。
为什么这样设计
数据准备的意义不在于「做变换」——那用 SQL 也能做——而在于 可重复性。一个保存好的流程会对刷新后的源数据重跑同样的联接与类型转换,于是下个月的文件里某列改了名时,仪表板不会悄悄腐坏。
画布
左侧面板列出你可以引入的东西,并按它所在的位置分组,这样你随时清楚自己碰的是本地副本还是活的系统:
- 本地表 ——已上传的文件和此前准备好的表,都已在工作区内。
- 外部表 ——已接入的数仓与数据库,按 schema.table 展开,这样你能看清自己选的到底是哪个对象。点击某一项会把一份有上限的快照带上画布供你设计,而不是把几百万行拉进浏览器。
拖入一张表让它成为基表,再加入更多表并连接起来。每一步都会实时预览结果行,于是联接出错你会立刻发现,而不是拖到最后。
orders ──┐
├── join (customer_id) ──▶ filter ──▶ computed column ──▶ prepared table
customers┘ status= margin =
'shipped' revenue - cost联接
选好两侧的键列和联接类型。四种类型,用平实的话说:
- 内联接
- 只保留两侧都匹配上的行。未匹配的行会被静默丢掉——之后记得核对行数。
- 左联接
- 保留基表的每一行;右侧缺失的值变成 null。当基表就是你的分析单元时,这是安全的默认选择。
- 右联接
- 左联接的镜像。通常把两张表调换位置、改用左联接会更清楚。
- 全联接
- 两侧全部保留。适合做对账——找出只在一侧存在的记录。
盯住行数
如果联接让行数翻倍,说明某一侧的键不唯一,于是下游每个度量都在重复计算。预览里的行数是发现这件事最省的办法。
列类型
每一列都带有类型,导入时设定,可在准备画布里修改。类型决定下游能用哪些筛选、聚合和图表,所以在这里弄对能省掉之后的排查。
| 类型 | 适用于 |
|---|---|
text | 自由文本 |
integer | 整数 |
decimal | 小数 |
date | 日期——日期筛选和时序图表必需 |
boolean | 真 / 假 |
location | 地名或地区代码——可启用地图类图表 |
category | 一小组反复出现的取值;天然的分组维度 |
currency | 金额——下游按货币格式显示 |
percent | 比率与占比 |
id | 标识符——不会出现在聚合建议里,因为把 id 加起来毫无意义 |
九种步骤
步骤按顺序生效。任何一步都可以删除,预览会随之更新。
| 步骤 | 作用 | 配置 |
|---|---|---|
计算字段 calc | 使用公式添加列 | 名称、表达式,以及结果列的类型 |
筛选行 filter | 仅保留符合条件的行 | 一个或多个条件,用 AND 或 OR |
汇总 aggregate | 分组汇总 | 分组列,加上度量(求和、平均、计数、去重计数、最小值、最大值) |
追加行 append | 合并另一个数据集中的行 | 源表、要保留的列,以及模式 all 或 distinct |
透视 pivot | 将行值转换为列 | 要展开的列,以及用什么值填充 |
逆透视 unpivot | 将列转换为行(宽表 → 长表) | 要逆透视的列,以及键 / 值两列的名称 |
拆分列 split | 将文本拆分到多列 | 源列与分隔符 |
移除重复项 dedupe | 删除重复行 | 由哪些列判定为重复 |
查找和替换 replace | 替换列中的值 | 列、匹配内容与替换内容 |
编写计算字段
表达式用的是 SQL,不是电子表格那套公式语言。它会被放进一条 SELECT 作为 (your expression) AS your_column_name里,所以凡是 SQL 选择列表里合法的东西都能用——算术、函数、 CASE,以及对流程中该位置可用的任意列的引用。
SQL
-- arithmetic across columns
revenue - cost
-- a rate, guarding the divide-by-zero that would otherwise produce nulls
CASE WHEN visits > 0 THEN conversions * 1.0 / visits ELSE 0 END
-- bucketing, for grouping later in the flow
CASE
WHEN amount >= 10000 THEN 'enterprise'
WHEN amount >= 1000 THEN 'mid-market'
ELSE 'smb'
END
-- text tidying
lower(trim(email))
-- a month key to summarise by
date_trunc('month', ordered_at)方言始终是 DuckDB
本地数据集在浏览器预览和服务端定时刷新时都跑在 DuckDB 上——刻意用同一个引擎,这样你在预览里看到的就是定时任务产出的。这意味着 DuckDB 的函数库你都可以用:
date_trunc, strftime, regexp_extract, list_aggregate、窗口函数,以及其余各项。顺序有影响,命名也有影响
步骤按顺序执行,所以计算字段只能引用位于它 之上 的那些列——包括更早的计算字段,而这正是分成若干可读片段层层搭建的预期用法。给每一个都起一个你乐意看到出现在图表坐标轴上的名字:它会成为一个真实的列,仪表板、度量和智能体都按这个名字引用它,之后改名会让所有已经指向它的东西失效。
筛选运算符
除了常规的比较运算符,大家常找的是文本类和空值类运算符: contains, starts with, ends with, is empty 和 is not empty.
「为空」不等于「等于空字符串」
一列里可以存真正的空字符串,也可以存 null,两者的筛选行为不同。如果某个筛选返回的行数比预期少,先查清你的数据里实际是哪一种—— 数据目录 里的列画像会显示空值率。
保存与刷新
- 1
保存流程
保存的是配方——数据源、联接、各步骤——而不只是产出结果。 - 2
运行它
产出(或替换)那张已准备表。它会出现在数据目录里,标记为「已准备」。 - 3
给它排计划
设一个刷新节奏,让这张已准备表按当前的源数据重建。建立在它之上的一切——仪表板、智能体、度量——都会跟着更新。
血缘
已准备表会记录它是由什么构建的,可在 数据目录里查看。删除或重构某张源表之前,先在那里看看有什么依赖它。
什么时候不该用数据准备
- 一次性的答案 ——直接在 SQL 工作台里写查询就行。
- 组织内必须达成一致的口径 ——「活跃客户」这类共用定义应该放进 语义层,在那里定义一次、处处复用,而不是烧死在某一张已准备表里。
- 超大表上的重型变换 ——把它下推到数仓里做,再把结果接进来。