阅读我们的文章

.

在日常工作中,Data Engineer 和 Data 分析师需要改进 data 采集流程。除了常规的单元测试外,出于影响分析或非回归测试等不同目的,简单快速地比较两个 data 集(即表、视图、查询等)可能也很有趣。此外,识别快照表的两个视角之间的差异对于临时分析或调试也非常有用。.

考虑到这一点,对于 SQL 从业人员来说,预置和可重复使用的脚本是有意义的,这也是本文的目的所在。.

即用型 SQL 模板说明

让我们带着期待的疑问直奔问题的核心:

Image

现在,让我们来解释一下:

  • 首先,我们使用 CTE - 常用表表达式(WITH ... ASstatements)来确定要比较的两个 data 集。因此,下面的查询行可以保持不变。.

  • 然后,我们构造两个类似的查询,别名分别为 dataset_1_only 和 dataset_2_only,以便保留只存在于 dataset 1 中的记录(与 dataset 2 相比),反之亦然,这要归功于 EXCEPT 集操作符。.

  • 最后,还定义了一个标志补充字段,以识别两个查询中不匹配记录的来源。然后通过 UNION ALL 集合操作符收集这些数据。.

注:显然,要使用上述查询,前提条件是要有两个具有可比字段的 datasets

图例

理论说完了,现在说说实践!假设一家超市想 检索所有产品 有资格在单个表格中按星期晋级的人数 晋升条件.

作为初步声明,我们认为以下产品有库存:

Image

根据第 1 周的晋升条件:

  • 10% 水果、蔬菜和香草货架折扣

dataset_1 是:

Image

第 2 周,晋级条件演变为:

  • 10% 水果和冰淇淋货架折扣

  • 20% 蔬菜货架折扣

  • 药材货架无折扣

data 管道演进生成 dataset_2:

Image

但是......我们对结果真的有信心吗?典型的问题有:

  • 是否有缺失或多余的行?

  • 在受影响的田块上实施的进化是否正确?

  • 未受影响的田块是否会出现倒退?

注意:即使通过一个小 dataset 的微不足道的示例,直观地回答上述问题似乎很容易,但在实际使用中,我们通常会面对来自复杂查询(转换、连接、聚合、窗口函数......)的大量行和列,这就使得该查询具有了完整的意义

让我们尝试通过解释对比查询结果来回答这 3 个问题:

Image

意见:

  • 与水果货架上的产品无缘: 纤细 作为“10% 水果折扣”从第 1 周到第 2 周,"...... "保持不变

  • dataset_2 中缺少产品编号 #50(药材架)(仅在 dataset_1 中): 纤细 作为“药材折扣”在第 2 周停止

  • dataset_1 中缺少 Product_ID #60(冰淇淋架)(仅在 dataset_2 中): 纤细 作为“冰淇淋折扣”于第 2 周推出

  • 有关 Product_ID #30 和 #40(蔬菜货架)的行在 reduced_price 字段上出现分歧: 纤细 作为“蔬菜折扣”从第 1 周的 10% 增加到第 2 周的 20%

最后,一切看起来都很好:

  • 是否有缺失或多余的行?

  • 在受影响的田块上实施的进化是否正确? 是的!

  • 未受影响的田块是否会出现倒退?

技巧和窍门

在 CTE 中,即使您可以复制粘贴摄取 SQL 查询的前后演变,也不妨 将结果保存在临时表格中 以简化比较,提高查询性能,并在多次运行时从缓存中获益。.

在现实世界中,两个 data 集之间的分歧可能会很混乱。那么, 结果排序 通过键(datasets 的粒度)和标志可以极大地帮助解释和比较来自两个 datasets 的等价行。.

为便于调查和确定差距的来源,《世界遗产名录》中的 可疑 datasets 公共领域 可以从比较中删除(即在 CTE 中注释):如果没有结果,说明所有比较字段都相等。然后,您就可以在下一次比较中只关注剩余的可疑字段,并逐步进行比较。.

注:可以使用 LEFT JOIN 策略进行等效分析,但维护起来会更加困难(空值和字段比较管理),效率也会更低,因为集合运算符比连接运算符更强大。.

摘要

因此,这种模板化查询能让开发人员更轻松地对复杂的 data 管道上的更改进行快速验证。它可以作为更传统的单元测试的补充,甚至可以在比较具有类似结构的任何两个 data 集时以更普遍的方式加以考虑。最后但并非最不重要的一点是,这种查询的逻辑甚至很容易背诵!

感谢您的阅读,希望我说得够清楚,也很高兴听到您的反馈意见 :)

中号 Blog by Artefact。.

本文最初发表于 Medium.com.
在我们的 Medium Blog 上关注我们!