SQLazy:辨识组内差异来源于品牌还是型号

问题描述

库表 tbl 的 ID 字段是汽车分类,每个分类再细分为品牌(Brand)和型号(Type)。现在要按 ID 分组,判断该组内汽车的差异来源:如果该组有多个品牌,则 Difference 为 Brand;如果该组有多个型号,则 Difference 为 Type。同一个 ID 可能产生多条记录。

源数据

ID

Brand

Type

1

Honda

Coupe

1

Jeep

SUV

2

Ford

Sedan

2

Ford

Crossover

期望结果

ID

Difference

1

Brand

1

Type

2

Type

ID=1 有 Honda 和 Jeep 两个品牌,以及 Coupe 和 SUV 两个型号,因此 Difference 同时产生 Brand 和 Type 两条记录。

ID=2 只有 Ford 一个品牌,但有 Sedan 和 Crossover 两个型号,因此只产生 Type 一条记录。

SQLazy 分步实现

核心思路:先用 summarize 按 ID 分组统计不重复的品牌数(cntBrand)和型号数(cntType),然后用 expand 将统计结果与待判断的维度(“Brand” 和 “Type”)做叉乘,最后用 filter 筛选出满足条件的行。

Name

Anchor

Statement

t1

tbl

summarize Brand icount as cntBrand, Type icount as cntType; group ID

t2


expand ["Brand","Type"] as Difference

t3


filter (if ((Difference = "Brand") then cntBrand>1; (Difference = "Type") then cntType>1))



derive ID, Difference

【点击在线运行本例】

下面逐一解释这些步骤。

第 1 步:按 ID 分组统计不重复的品牌数和型号数

summarize Brand icount as cntBrand, Type icount as cntType; group ID

用 summarize 功能按 ID 分组,icount 函数统计组内不重复的 Brand 和 Type 数量,分别记为 cntBrand 和 cntType。这一步将每组明细数据压缩为每个 ID 一行,包含不重复计数。

Picture1png

第 2 步:将维度列表展开为行

expand ["Brand","Type"] as Difference

expand 功能将常量列表 ["Brand","Type"] 展开为行,与上一步每行做叉乘,生成新列 Difference。这样每个 ID 都会产生 Difference="Brand" 和 Difference="Type" 两条记录,同时保留 cntBrand 和 cntType 字段。

Picture2png

第 3 步:筛选满足条件的维度

filter (if ((Difference = "Brand") then cntBrand>1; (Difference = "Type") then cntType>1))

用 filter 功能配合条件分支语法,对 Difference="Brand" 的行筛选出 cntBrand>1 的记录,对 Difference="Type" 的行筛选出 cntType>1 的记录。

Picture3png

第 4 步:选取结果中需要的列

derive ID, Difference

Picture4png

编译生成 SQL

确认上述步骤后,SQLazy 编译器自动生成原生 SQL(PostgreSQL 语法):

WITH Value1 AS (
  SELECT
    ID,
    COUNT(DISTINCT Brand) AS cntBrand,
    COUNT(DISTINCT Type) AS cntType
  FROM (
    SELECT ID, Brand, Type FROM tbl
  ) tbl
  GROUP BY ID
),
Value2 AS (
  SELECT
    Value1.ID, Value1.cntBrand, Value1.cntType, Difference
  FROM Value1
  CROSS JOIN (
    SELECT 'Brand' AS Difference
    UNION ALL
    SELECT 'Type'
  ) T_1
)
SELECT ID, Difference FROM Value2
WHERE CASE
  WHEN (Difference = 'Brand') THEN cntBrand > 1
  WHEN (Difference = 'Type') THEN cntType > 1
  ELSE NULL
END

SQLazy 让你用业务语言描述逻辑,而不是用 SQL 语法写嵌套查询。解题过程分 4 步,每步都可独立验证中间结果,降低了复杂逻辑的出错概率。summarize 功能的 icount 函数可以直接统计不重复值数量,一行代码替代 SQL 的 COUNT(DISTINCT ...)。expand 功能将常量列表展开为行,一行代码完成 SQL 中 CROSS JOIN 配合 UNION ALL 的多步操作。filter 功能的条件分支语法(if ... then ...; ... then ...)让多条件筛选逻辑一目了然,比 SQL 的 CASE WHEN 嵌套更清晰。

官方链接

SQLazy 在线体验sqlazy.com(免费,无需注册)
SQLazy 项目仓库github.com/SPLWare/SQLazy