SQLazy: 按订单 SKU 条件分配仓库
问题描述
订单明细表记录了每笔订单的 ORDER_NUMBER、SKU 和 WEBSITE。现在需要按整单判断:如果同一订单中存在 SKU 为 10000 或 20000 的行,或者网站不是 EU SITE,则整单所有行分配 WAREHOUSE 1;否则分配 WAREHOUSE 2。新增字段 FULFILLED_BY。
源数据
ORDER_NUMBER |
SKU |
WEBSITE |
10001 |
10000 |
EU SITE |
10001 |
15123 |
EU SITE |
10002 |
20000 |
EU SITE |
10002 |
28467 |
EU SITE |
10003 |
15123 |
EU SITE |
10003 |
15124 |
EU SITE |
10004 |
10000 |
US SITE |
10005 |
15123 |
US SITE |
10006 |
10000 |
EU SITE |
10007 |
28467 |
EU SITE |
期望结果
ORDER_NUMBER |
SKU |
WEBSITE |
FULFILLED_BY |
10001 |
10000 |
EU SITE |
WAREHOUSE 1 |
10001 |
15123 |
EU SITE |
WAREHOUSE 1 |
10002 |
20000 |
EU SITE |
WAREHOUSE 1 |
10002 |
28467 |
EU SITE |
WAREHOUSE 1 |
10003 |
15123 |
EU SITE |
WAREHOUSE 2 |
10003 |
15124 |
EU SITE |
WAREHOUSE 2 |
10004 |
10000 |
US SITE |
WAREHOUSE 1 |
10005 |
15123 |
US SITE |
WAREHOUSE 1 |
10006 |
10000 |
EU SITE |
WAREHOUSE 1 |
10007 |
28467 |
EU SITE |
WAREHOUSE 2 |
以几个有代表性的订单为例:
订单 10001、10002:包含特殊 SKU 10000 或 20000,整单分配 WAREHOUSE 1。
订单 10003:均为 EU SITE 且不含特殊 SKU,整单分配 WAREHOUSE 2。
订单 10004、10005:网站为 US SITE(非 EU),整单分配 WAREHOUSE 1。订单 10007:单行订单,非特殊 SKU,EU 站点,分配 WAREHOUSE 2。
SQLazy 分步实现
核心思路:按订单分组,用 compute 的 max 聚合判断订单中是否存在特殊 SKU,再根据聚合结果和 WEBSITE 条件,在同一个 compute 中计算出整单的 FULFILLED_BY。
Name |
Anchor |
Statement |
t1 |
tb_detail |
compute if (([10000,20000] contain SKU)then 1 else 0) max as order_has_special; if (order_has_special = 1 or WEBSITE <> "EU SITE" then "WAREHOUSE 1" else "WAREHOUSE 2") as FULFILLED_BY; partition ORDER_NUMBER |
derive ORDER_NUMBER, SKU, WEBSITE, FULFILLED_BY |
下面逐一解释这些步骤。
第 1 步:按订单分组计算分配仓库(核心)
compute if (([10000,20000] contain SKU)then 1 else 0) max as order_has_special; if (order_has_special = 1 or WEBSITE <> "EU SITE" then "WAREHOUSE 1" else "WAREHOUSE 2") as FULFILLED_BY; partition ORDER_NUMBER
这是核心的一步。一个 compute 语句中计算了两个字段:order_has_special,对订单内的每一行判断 SKU 是否在列表 [10000,20000] 中,用 contain 做集合成员检查,再以 max 聚合到订单级别——只要订单中任意一行命中,max 结果就是 1。 FULFILLED_BY:利用上一步的聚合结果,当 order_has_special=1 或 WEBSITE 不是 EU SITE 时分配 WAREHOUSE 1,否则分配 WAREHOUSE 2。partition ORDER_NUMBER 确保聚合和计算都在订单级别。

第 2 步:选择最终输出列
derive ORDER_NUMBER, SKU, WEBSITE, FULFILLED_BY
用 derive 保留需要的四列,去掉辅助字段 order_has_special,输出最终结果。

编译生成 SQL
确认上述步骤后,SQLazy 编译器自动生成原生 SQL(Snowflake 语法):
WITH tb_detail_1 AS (
SELECT ORDER_NUMBER, SKU, WEBSITE
, MAX(CASE
WHEN SKU IN (10000, 20000) THEN 1
ELSE 0
END) OVER (PARTITION BY ORDER_NUMBER) AS order_has_special
FROM tb_detail
),
t1 AS (
SELECT ORDER_NUMBER, SKU, WEBSITE, order_has_special
, CASE
WHEN order_has_special = 1
OR WEBSITE <> 'EU SITE'
THEN 'WAREHOUSE 1'
ELSE 'WAREHOUSE 2'
END AS FULFILLED_BY
FROM tb_detail_1
)
SELECT ORDER_NUMBER, SKU, WEBSITE, FULFILLED_BY
FROM t1
SQLazy 让你用业务语言描述逻辑,而不是用 SQL 语法写嵌套查询。这个例子用 compute 语句完成 "先按订单聚合出标记、再基于标记分配" 的两层逻辑,无需像 SQL 那样先写一个 CTE 做 MAX(CASE WHEN ... IN ...) OVER 窗口聚合,再写另一个 CTE 做 CASE WHEN 判断。compute 的 partition 子句将 "订单级计算" 的语义直接表达出来,contain 函数让 "集合成员检查" 像日常语言一样可读。分步计算让每一步的中间结果都可独立验证,降低了整体逻辑的出错概率。
官方链接
SQLazy 在线体验:sqlazy.com(免费,无需注册)
SQLazy 项目仓库:github.com/SPLWare/SQLazy

英文版 https://c.esproc.com/article/1784885979940