SQL 嵌套逻辑
SQL nested logic
这是我的table结构
CUST_ID ORDER_DT
1 01-2013
1 04-2013
1 01-2015
1 02-2015
我想要实现的是将客户分类为新 customer/existing 客户并恢复。
逻辑是
第一次订货-新
从上次购买到现有的 365 天内的时间
时间超过 1 年然后复活
我的输出应该是
CUST_ID ORDER_DT FLAG
1 01-2013 New
1 04-2013 Exisiting
1 01-2015 Revived
1 02-2015 Exisiting
我的SQL
select a.cust_id,a.order_dt,coalesce(b.ptye,'other') as typ
from tab a left join
(select min(order_dt),new as ptye from tab group by cust_id) b on a.cust_id=b.cust_id
如何用嵌套逻辑替换另一个。
一个非常简单的方法是使用带子查询的 case 语句:
select cust_id
, order_dt
, flag = case
when (select COUNT(*) from myTable x where t.cust_id= x.cust_id and x.order_dt < t.order_dt and DATEDIFF(DD, x.order_dt , t.order_dt ) < 365) then 'Existing'
when (select COUNT(*) from myTable x where t.cust_id= x.cust_id and x.order_dt < t.order_dt and DATEDIFF(DD, x.order_dt , t.order_dt ) >= 365) then 'Revived'
else 'New'
end
from myTable t
最好的方法是使用 lag()
。 Teradata 不太支持延迟,但它确实支持其他 window 功能。所以,你可以模仿一下:
select t.cust_id, t.order_dt,
(case when order_dt - prev_od <= 365 then 'Existing' else 'New'
end) as flag
from (select t.*,
max(order_dt) over (partition by cust_id order by order_dt
rows between 1 preceding and 1 preceding
) as prevod
from mytable t
) t;
我应该指出您实际上不需要子查询,但我认为它有助于提高可读性:
select t.cust_id, t.order_dt,
(case when order_dt -
max(order_dt) over (partition by cust_id order by order_dt
rows between 1 preceding and 1 preceding
) <= 365
then 'Existing' else 'New'
end) as flag
from (select t.*,
as prevod
from mytable t
) t;
这包括 Gordon 的回答中缺少的 "revived" 逻辑:
SELECT
CUST_ID, ORDER_DT,
CASE
WHEN ORDER_DT = MIN(ORDER_DT) -- first order
OVER (PARTITION BY CUST_ID)
THEN 'New'
WHEN ORDER_DT >= MAX(ORDER_DT) -- more than 365 days since previous order
OVER (PARTITION BY CUST_ID
ORDER BY ORDER_DT
ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) + 365
THEN 'Revived'
ELSE 'Existing'
END
FROM tab
这是我的table结构
CUST_ID ORDER_DT
1 01-2013
1 04-2013
1 01-2015
1 02-2015
我想要实现的是将客户分类为新 customer/existing 客户并恢复。 逻辑是 第一次订货-新 从上次购买到现有的 365 天内的时间 时间超过 1 年然后复活
我的输出应该是
CUST_ID ORDER_DT FLAG
1 01-2013 New
1 04-2013 Exisiting
1 01-2015 Revived
1 02-2015 Exisiting
我的SQL
select a.cust_id,a.order_dt,coalesce(b.ptye,'other') as typ
from tab a left join
(select min(order_dt),new as ptye from tab group by cust_id) b on a.cust_id=b.cust_id
如何用嵌套逻辑替换另一个。
一个非常简单的方法是使用带子查询的 case 语句:
select cust_id
, order_dt
, flag = case
when (select COUNT(*) from myTable x where t.cust_id= x.cust_id and x.order_dt < t.order_dt and DATEDIFF(DD, x.order_dt , t.order_dt ) < 365) then 'Existing'
when (select COUNT(*) from myTable x where t.cust_id= x.cust_id and x.order_dt < t.order_dt and DATEDIFF(DD, x.order_dt , t.order_dt ) >= 365) then 'Revived'
else 'New'
end
from myTable t
最好的方法是使用 lag()
。 Teradata 不太支持延迟,但它确实支持其他 window 功能。所以,你可以模仿一下:
select t.cust_id, t.order_dt,
(case when order_dt - prev_od <= 365 then 'Existing' else 'New'
end) as flag
from (select t.*,
max(order_dt) over (partition by cust_id order by order_dt
rows between 1 preceding and 1 preceding
) as prevod
from mytable t
) t;
我应该指出您实际上不需要子查询,但我认为它有助于提高可读性:
select t.cust_id, t.order_dt,
(case when order_dt -
max(order_dt) over (partition by cust_id order by order_dt
rows between 1 preceding and 1 preceding
) <= 365
then 'Existing' else 'New'
end) as flag
from (select t.*,
as prevod
from mytable t
) t;
这包括 Gordon 的回答中缺少的 "revived" 逻辑:
SELECT
CUST_ID, ORDER_DT,
CASE
WHEN ORDER_DT = MIN(ORDER_DT) -- first order
OVER (PARTITION BY CUST_ID)
THEN 'New'
WHEN ORDER_DT >= MAX(ORDER_DT) -- more than 365 days since previous order
OVER (PARTITION BY CUST_ID
ORDER BY ORDER_DT
ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) + 365
THEN 'Revived'
ELSE 'Existing'
END
FROM tab