【问题标题】:Limiting records by included/excluded/null date ranges按包含/排除/空日期范围限制记录
【发布时间】:2020-04-08 19:02:06
【问题描述】:

首先,我的任务描述。我需要确定在过去 2 年内下订单的客户。但是,我需要这些记录的一个子集。

  1. 需要在 12-24 个月前下达 1 个或多个订单。
  2. NO 订单在 1-12 个月前下达的间隔。
  3. 在过去一个月内下达了 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))

SAMPLE DATA:(我没有看到添加表格的方法,所以这里...)

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

我并没有像现在这样与我的代码结婚。我希望有人能引导我找到更好的方法来完成这项任务。

谢谢!

-道格伯特

【问题讨论】:

  • 我还没有测试整个事情,但它正在寻找seq 同时是12 的行。您可能需要or 而不是and
  • 我也不确定date_entered 可以同时是&gt;= add_months(trunc(sysdate), -1)&lt; add_months(trunc(sysdate), -12)

标签: sql oracle gaps-in-data


【解决方案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 表。你写它的方式基本上意味着“在 1 到 12 个月前,存在来自任何客户的订单”。

【讨论】:

  • 感谢 eaolson!我只需要更改您的 2 个别名。
  • (2nd) WHERE a2.customer_id = a1.customer_id a2 需要是 a3 (4th) WHERE a2.customer_id = a1.customer_id a2 需要是 a4 运行它并提供了以下清单让我能够积极地识别每个符合标准的客户,这是我需要开始的。最终,我将改进您的代码,以便在生产中使用它。我真的很感谢你的时间和精力,以及关于我误入歧途的额外信息。
  • 抱歉,剪切粘贴失败。我想我已经更正了后代的查询。
【解决方案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;

【讨论】:

  • 谢谢 Gordon,我直接去了客户专用代码。顺便说一句:我通过远程连接到我们的 IFS (ERP) Oracle 服务器并在服务器上使用 SQL Developer 运行我的查询。因为我在生产服务器上运行它,所以我只对您的代码进行了轻微修改。它挂在第 8 行第 1 列,这将是 WHERE 子句。错误消息指出“ORA-00933:SQL 命令未正确结束”。所以,我认为它不喜欢放在 WHERE 之前的 GROUP BY 子句。之后移动 GROUP BY 会产生相同的错误代码。有什么想法吗?
【解决方案3】:

如果以后有人提到我的问题,我想分享我的最终生产解决方案。因此,为了获得我需要的输出,需要进行一些更改。

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 帮助我到达我需要去的地方。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-23
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    • 2013-04-14
    • 2012-10-10
    相关资源
    最近更新 更多