按 included/excluded/null 个日期范围限制记录
Limiting records by included/excluded/null date ranges
首先,描述一下我的任务。我需要确定过去 2 年内下过订单的客户。但是,我需要这些记录的一个子集。
- 需要在 12-24 个月前下过 1 个或多个订单。
- 1-12 个月前 没有 订单。
- 过去一个月内下了 1 个或多个新订单。
听起来很简单,但我花了太多时间来隔离约束而没有收到所需的输出。
这是我当前的代码尝试:
SELECT * FROM
(SELECT CUSTOMER_ID AS "CUSTOMER", NAME, DATE_ENTERED,
ROW_NUMBER() OVER(PARTITION BY CUSTOMER_ID
ORDER BY DATE_ENTERED desc) SEQ
FROM
A_ATEST
WHERE
DATE_ENTERED >= ADD_MONTHS(TRUNC(sysdate),-24) AND
(DATE_ENTERED >= ADD_MONTHS(TRUNC(sysdate),-1) AND
DATE_ENTERED < ADD_MONTHS(TRUNC(sysdate),-12)) AND
NOT EXISTS(SELECT null FROM A_ATEST WHERE
DATE_ENTERED < ADD_MONTHS(TRUNC(sysdate),-1) AND
DATE_ENTERED > ADD_MONTHS(TRUNC(sysdate),-12))
) a
WHERE
(SEQ = 1 AND
DATE_ENTERED >= ADD_MONTHS(TRUNC(sysdate),-1)) AND
(SEQ = 2 AND
DATE_ENTERED < ADD_MONTHS(TRUNC(sysdate),-12))
示例数据:(我看不到添加 table 的方法,所以这里...)
CUSTOMER, NAME, DATE_ENTERED
100 A 08-APR-20
100 A 01-MAR-20
100 A 01-MAR-20
101 B 09-MAR-20
101 B 07-MAR-19
101 B 01-MAR-19
102 C 04-APR-20
102 C 03-JAN-19
102 C 05-JAN-18
理想情况下,我当前代码的结果集应显示:
CUSTOMER, NAME, DATE_ENTERED, SEQ
102 C 04-APR-20 1
102 C 03-JAN-19 2
我不喜欢我的代码。我希望有人能引导我找到更好的方法来完成这项任务。
谢谢!
-杜格伯特
您需要最近两年的订单,间隔一年。这表明 lag()
:
select a.*
from (select a.*,
max(case when prev_de < add_months(date_entered, -12) then 1 else 0 end) over (partition by customer_id) as has_12month_gap
from (select a.*,
lag(date_entered) over (partition by CUSTOMER_ID order by date_entered) as prev_de,
max(date_entered) over (partition by customer_id) as max_de
from A_ATEST a
where date_entered > add_months(sysdate, -24)
) a
) a
where max_de > add_months(sysdate, -1) and
has_12month_gap = 1;
编辑:
以上带回了所有交易。仅对客户而言,也是类似的逻辑,但更简单一些:
select customer
from (select a.*,
lag(date_entered) over (partition by CUSTOMER_ID order by date_entered) as prev_de
from A_ATEST a
where date_entered > add_months(sysdate, -24)
) a
group by customer
where max(date_entered) > add_months(sysdate, -1) and
max(case when prev_de < add_months(date_entered, -12) then 1 else 0 end) = 1;
我想这会给你想要的。你的问题说你想要客户列表,但你的输出数据表明你想要这些客户的订单列表。
SELECT CUSTOMER_ID AS "CUSTOMER", NAME, DATE_ENTERED,
FROM A_ATEST a1
WHERE a1.DATE_ENTERED >= ADD_MONTHS(TRUNC(sysdate),-24)
AND EXISTS ( SELECT 1 FROM A_ATEST a3
WHERE a3.customer_id = a1.customer_id
AND a3.DATE_ENTERED BETWEEN ADD_MONTHS(TRUNC(sysdate), -24)
AND ADD_MONTHS(TRUNC(sysdate), -12))
AND NOT EXISTS ( SELECT 1 FROM A_ATEST a2
WHERE a2.customer_id = a1.customer_id
AND DATE_ENTERED < ADD_MONTHS(TRUNC(sysdate), -1)
AND DATE_ENTERED > ADD_MONTHS(TRUNC(sysdate), -12))
AND EXISTS ( SELECT 1 FROM A_ATEST a4
WHERE a4.customer_id = a1.customer_id
AND a4.DATE_ENTERED > ADD_MONTHS(TRUNC(sysdate), -12))
这里的关键是您的子查询需要将 customer_id 关联回最外层的 A_ATEST
table。你写的方式基本上意味着 "and there exists an order from any customer between 1 and 12 months ago".
如果以后有人提到我的问题,我想分享我最终的生产解决方案。因此,有许多更改以获得我需要的输出。
SELECT DISTINCT a1.CUSTOMER_NO AS "CUSTOMER", ci.NAME, MAX(a1.DATE_ENTERED) AS "ORDER DATE", a1.SALESMAN_CODE AS "SALESPERSON"
FROM CUSTOMER_INFO ci LEFT JOIN CUSTOMER_ORDER a1 ON ci.CUSTOMER_ID = a1.CUSTOMER_NO
WHERE a1.DATE_ENTERED >= ADD_MONTHS(TRUNC(sysdate), -1)
AND EXISTS ( SELECT 1 FROM CUSTOMER_ORDER a3
WHERE a3.customer_no = a1.customer_no
AND a3.DATE_ENTERED BETWEEN ADD_MONTHS(TRUNC(sysdate), -24)
AND ADD_MONTHS(TRUNC(sysdate), -12))
AND NOT EXISTS ( SELECT 1 FROM CUSTOMER_ORDER a2
WHERE a2.customer_no = a1.customer_no
AND DATE_ENTERED < ADD_MONTHS(TRUNC(sysdate), -1)
AND DATE_ENTERED > ADD_MONTHS(TRUNC(sysdate), -12))
AND EXISTS ( SELECT 1 FROM CUSTOMER_ORDER a4
WHERE a4.customer_no = a1.customer_no
AND a4.DATE_ENTERED > ADD_MONTHS(TRUNC(sysdate), -24))
GROUP BY a1.CUSTOMER_NO, ci.NAME, a1.SALESMAN_CODE
ORDER BY a1.CUSTOMER_NO, "ORDER DATE"
再次感谢 eaolson 和 Gordon Linoff 帮助我到达我需要去的地方。
首先,描述一下我的任务。我需要确定过去 2 年内下过订单的客户。但是,我需要这些记录的一个子集。
- 需要在 12-24 个月前下过 1 个或多个订单。
- 1-12 个月前 没有 订单。
- 过去一个月内下了 1 个或多个新订单。
听起来很简单,但我花了太多时间来隔离约束而没有收到所需的输出。
这是我当前的代码尝试:
SELECT * FROM
(SELECT CUSTOMER_ID AS "CUSTOMER", NAME, DATE_ENTERED,
ROW_NUMBER() OVER(PARTITION BY CUSTOMER_ID
ORDER BY DATE_ENTERED desc) SEQ
FROM
A_ATEST
WHERE
DATE_ENTERED >= ADD_MONTHS(TRUNC(sysdate),-24) AND
(DATE_ENTERED >= ADD_MONTHS(TRUNC(sysdate),-1) AND
DATE_ENTERED < ADD_MONTHS(TRUNC(sysdate),-12)) AND
NOT EXISTS(SELECT null FROM A_ATEST WHERE
DATE_ENTERED < ADD_MONTHS(TRUNC(sysdate),-1) AND
DATE_ENTERED > ADD_MONTHS(TRUNC(sysdate),-12))
) a
WHERE
(SEQ = 1 AND
DATE_ENTERED >= ADD_MONTHS(TRUNC(sysdate),-1)) AND
(SEQ = 2 AND
DATE_ENTERED < ADD_MONTHS(TRUNC(sysdate),-12))
示例数据:(我看不到添加 table 的方法,所以这里...)
CUSTOMER, NAME, DATE_ENTERED
100 A 08-APR-20
100 A 01-MAR-20
100 A 01-MAR-20
101 B 09-MAR-20
101 B 07-MAR-19
101 B 01-MAR-19
102 C 04-APR-20
102 C 03-JAN-19
102 C 05-JAN-18
理想情况下,我当前代码的结果集应显示:
CUSTOMER, NAME, DATE_ENTERED, SEQ
102 C 04-APR-20 1
102 C 03-JAN-19 2
我不喜欢我的代码。我希望有人能引导我找到更好的方法来完成这项任务。
谢谢!
-杜格伯特
您需要最近两年的订单,间隔一年。这表明 lag()
:
select a.*
from (select a.*,
max(case when prev_de < add_months(date_entered, -12) then 1 else 0 end) over (partition by customer_id) as has_12month_gap
from (select a.*,
lag(date_entered) over (partition by CUSTOMER_ID order by date_entered) as prev_de,
max(date_entered) over (partition by customer_id) as max_de
from A_ATEST a
where date_entered > add_months(sysdate, -24)
) a
) a
where max_de > add_months(sysdate, -1) and
has_12month_gap = 1;
编辑:
以上带回了所有交易。仅对客户而言,也是类似的逻辑,但更简单一些:
select customer
from (select a.*,
lag(date_entered) over (partition by CUSTOMER_ID order by date_entered) as prev_de
from A_ATEST a
where date_entered > add_months(sysdate, -24)
) a
group by customer
where max(date_entered) > add_months(sysdate, -1) and
max(case when prev_de < add_months(date_entered, -12) then 1 else 0 end) = 1;
我想这会给你想要的。你的问题说你想要客户列表,但你的输出数据表明你想要这些客户的订单列表。
SELECT CUSTOMER_ID AS "CUSTOMER", NAME, DATE_ENTERED,
FROM A_ATEST a1
WHERE a1.DATE_ENTERED >= ADD_MONTHS(TRUNC(sysdate),-24)
AND EXISTS ( SELECT 1 FROM A_ATEST a3
WHERE a3.customer_id = a1.customer_id
AND a3.DATE_ENTERED BETWEEN ADD_MONTHS(TRUNC(sysdate), -24)
AND ADD_MONTHS(TRUNC(sysdate), -12))
AND NOT EXISTS ( SELECT 1 FROM A_ATEST a2
WHERE a2.customer_id = a1.customer_id
AND DATE_ENTERED < ADD_MONTHS(TRUNC(sysdate), -1)
AND DATE_ENTERED > ADD_MONTHS(TRUNC(sysdate), -12))
AND EXISTS ( SELECT 1 FROM A_ATEST a4
WHERE a4.customer_id = a1.customer_id
AND a4.DATE_ENTERED > ADD_MONTHS(TRUNC(sysdate), -12))
这里的关键是您的子查询需要将 customer_id 关联回最外层的 A_ATEST
table。你写的方式基本上意味着 "and there exists an order from any customer between 1 and 12 months ago".
如果以后有人提到我的问题,我想分享我最终的生产解决方案。因此,有许多更改以获得我需要的输出。
SELECT DISTINCT a1.CUSTOMER_NO AS "CUSTOMER", ci.NAME, MAX(a1.DATE_ENTERED) AS "ORDER DATE", a1.SALESMAN_CODE AS "SALESPERSON"
FROM CUSTOMER_INFO ci LEFT JOIN CUSTOMER_ORDER a1 ON ci.CUSTOMER_ID = a1.CUSTOMER_NO
WHERE a1.DATE_ENTERED >= ADD_MONTHS(TRUNC(sysdate), -1)
AND EXISTS ( SELECT 1 FROM CUSTOMER_ORDER a3
WHERE a3.customer_no = a1.customer_no
AND a3.DATE_ENTERED BETWEEN ADD_MONTHS(TRUNC(sysdate), -24)
AND ADD_MONTHS(TRUNC(sysdate), -12))
AND NOT EXISTS ( SELECT 1 FROM CUSTOMER_ORDER a2
WHERE a2.customer_no = a1.customer_no
AND DATE_ENTERED < ADD_MONTHS(TRUNC(sysdate), -1)
AND DATE_ENTERED > ADD_MONTHS(TRUNC(sysdate), -12))
AND EXISTS ( SELECT 1 FROM CUSTOMER_ORDER a4
WHERE a4.customer_no = a1.customer_no
AND a4.DATE_ENTERED > ADD_MONTHS(TRUNC(sysdate), -24))
GROUP BY a1.CUSTOMER_NO, ci.NAME, a1.SALESMAN_CODE
ORDER BY a1.CUSTOMER_NO, "ORDER DATE"
再次感谢 eaolson 和 Gordon Linoff 帮助我到达我需要去的地方。