选取最早的日期记录 – Oracle SQL

huangapple go评论65阅读模式
英文:

Pick the earliest date record -Oracle sql

问题

我在Oracle SQL中有一个疑问,我需要根据日期范围选择最早的记录。我有一个名为A的表,其中包含如下数据:

SYM_RUN_DATE CLIENT_NO CLIENT_STATUS
2023-03-31 00019872 2
2023-03-30 00019872 2
2023-03-29 00019872 2
2023-03-28 00019872 2
2023-03-27 00019872 1
2023-03-26 00019872 1
2023-03-25 00019872 1
2023-03-24 00019872 2
2023-03-23 00019872 2
2023-03-22 00019872 2
2023-03-21 00019872 2
2023-03-20 00019872 2
2023-03-19 00019872 2
2023-03-18 00019872 1
2023-03-17 00019872 1
2023-03-16 00019872 1

我需要的结果输出应该是(CLIENT_STATUS=2):

SYM_RUN_DATE CLIENT_NO CLIENT_STATUS
2023-03-28 00019872 2

请告诉我如何在Oracle SQL中实现这个目标。

英文:

I have a doubt in Oracle SQl, I have to pick the earliest record based on date ranges. I have table A with

SYM_RUN_DATE CLIENT_NO CLIENT_STATUS
2023-03-31 00019872 2
2023-03-30 00019872 2
2023-03-29 00019872 2
2023-03-28 00019872 2
2023-03-27 00019872 1
2023-03-26 00019872 1
2023-03-25 00019872 1
2023-03-24 00019872 2
2023-03-23 00019872 2
2023-03-22 00019872 2
2023-03-21 00019872 2
2023-03-20 00019872 2
2023-03-19 00019872 2
2023-03-18 00019872 1
2023-03-17 00019872 1
2023-03-16 00019872 1

My resulting output should be (CLIENT_STATUS=2)

SYM_RUN_DATE CLIENT_NO CLIENT_STATUS
2023-03-28 00019872 2

Please let me know how it can be achieved in oracle sql

答案1

得分: 1

以下是翻译好的部分:

如果您想要在具有最新client_status的行集中获取最早的行,可以使用MATCH_RECOGNIZE来执行逐行处理:

SELECT *
FROM   table_name
MATCH_RECOGNIZE(
  ORDER BY sym_run_date DESC
  ALL ROWS PER MATCH
  PATTERN (^ {- (same_status*) -} next_row )
  DEFINE same_status AS client_status = NEXT(client_status)
)

或者,您可以使用分析函数:

SELECT SYM_RUN_DATE,
       CLIENT_NO,
       CLIENT_STATUS
FROM   (
  SELECT SYM_RUN_DATE,
         CLIENT_NO,
         CLIENT_STATUS,
         ROW_NUMBER() OVER (ORDER BY sym_run_date DESC)
           - ROW_NUMBER() OVER (PARTITION BY client_status ORDER BY sym_run_date DESC) AS grp
  FROM   table_name
)
WHERE   grp = 0
ORDER BY sym_run_date
FETCH FIRST ROW ONLY;

对于示例数据:

CREATE TABLE table_name (SYM_RUN_DATE, CLIENT_NO, CLIENT_STATUS) AS
SELECT DATE '2023-03-31', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-30', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-29', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-28', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-27', '00019872', 1 FROM DUAL UNION ALL
SELECT DATE '2023-03-26', '00019872', 1 FROM DUAL UNION ALL
SELECT DATE '2023-03-25', '00019872', 1 FROM DUAL UNION ALL
SELECT DATE '2023-03-24', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-23', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-22', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-21', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-20', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-19', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-18', '00019872', 1 FROM DUAL UNION ALL
SELECT DATE '2023-03-17', '00019872', 1 FROM DUAL UNION ALL
SELECT DATE '2023-03-16', '00019872', 1 FROM DUAL;

两种方法的输出都是:

SYM_RUN_DATE CLIENT_NO CLIENT_STATUS
2023-03-28 00:00:00 00019872 2

fiddle

英文:

If you want the earliest row in the set of rows with the latest client_status then, using MATCH_RECOGNIZE to perform row-by-row processing:

SELECT *
FROM   table_name
MATCH_RECOGNIZE(
  ORDER BY sym_run_date DESC
  ALL ROWS PER MATCH
  PATTERN (^ {- (same_status*) -} next_row )
  DEFINE same_status AS client_status = NEXT(client_status)
)

or, using analytic functions:

SELECT SYM_RUN_DATE,
       CLIENT_NO,
       CLIENT_STATUS
FROM   (
  SELECT SYM_RUN_DATE,
         CLIENT_NO,
         CLIENT_STATUS,
         ROW_NUMBER() OVER (ORDER BY sym_run_date DESC)
           - ROW_NUMBER() OVER (PARTITION BY client_status ORDER BY sym_run_date DESC) AS grp
  FROM   table_name
)
WHERE   grp = 0
ORDER BY sym_run_date
FETCH FIRST ROW ONLY;

Which, for the sample data:

CREATE TABLE table_name (SYM_RUN_DATE, CLIENT_NO, CLIENT_STATUS) AS
SELECT DATE '2023-03-31', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-30', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-29', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-28', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-27', '00019872', 1 FROM DUAL UNION ALL
SELECT DATE '2023-03-26', '00019872', 1 FROM DUAL UNION ALL
SELECT DATE '2023-03-25', '00019872', 1 FROM DUAL UNION ALL
SELECT DATE '2023-03-24', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-23', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-22', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-21', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-20', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-19', '00019872', 2 FROM DUAL UNION ALL
SELECT DATE '2023-03-18', '00019872', 1 FROM DUAL UNION ALL
SELECT DATE '2023-03-17', '00019872', 1 FROM DUAL UNION ALL
SELECT DATE '2023-03-16', '00019872', 1 FROM DUAL;

Both output:

SYM_RUN_DATE CLIENT_NO CLIENT_STATUS
2023-03-28 00:00:00 00019872 2

fiddle

答案2

得分: 0

使用row_number()函数可以方便地获取与日期范围匹配的最小日期的单行数据,例如:

SELECT
      SYM_RUN_DATE
    , CLIENT_NO
    , CLIENT_STATUS
FROM (
    SELECT
          SYM_RUN_DATE
        , CLIENT_NO
        , CLIENT_STATUS
        , row_number() OVER (ORDER BY SYM_RUN_DATE ASC) AS rn
    FROM tablea
    WHERE SYM_RUN_DATE > to_date('2023-03-27')
            AND SYM_RUN_DATE <= to_date('2023-04-23')
    ) d
WHERE rn = 1

在这里,row_number()函数从最旧的日期开始,每行递增1。在外部查询中,我们只请求具有生成的rn为1的行。请注意,是order by决定了行编号序列的生成方式。升序会使最旧的日期行为1,而降序会使最近的日期行为1。还要注意,如果有多行具有相同的最旧日期,则此方法仍然只返回1行。

英文:

A convenient method to arrive at a single row that matches a minimum date with a date range is to use row_number() e.g:

SELECT
      SYM_RUN_DATE
    , CLIENT_NO
    , CLIENT_STATUS
FROM (
    SELECT
          SYM_RUN_DATE
        , CLIENT_NO
        , CLIENT_STATUS
        , row_number() OVER (ORDER BY SYM_RUN_DATE ASC) AS rn
    FROM tablea
    WHERE SYM_RUN_DATE &gt; to_date(&#39;2023-03-27&#39;)
            AND SYM_RUN_DATE &lt;= to_date(&#39;2023-04-23&#39;)
    ) d
WHERE rn = 1

Here the row_number() function starts at 1 for the oldest date and increments by 1 for each subsequent row. In the outer query we simply ask for only that row haveing that generated rn of 1. Note that is the order by that determines how the row numbering sequence is generated. An ascending order make the oldest date row 1, whereas a descending order would make the most recent date row 1. Also not that if there are more than one row with the same oldest date you will still only get 1 row returned by this method.

答案3

得分: 0

我不特别喜欢这种方法,但目前找不到更好的方法。

示例数据:

SQL> select * From test order by sym_run_date desc;

SYM_RUN_DA CLIENT_N CLIENT_STATUS
---------- -------- -------------
2023-03-31 00019872 2
2023-03-30 00019872 2
2023-03-29 00019872 2
2023-03-28 00019872 2
2023-03-27 00019872 1
2023-03-26 00019872 1
2023-03-25 00019872 1
2023-03-24 00019872 2
2023-03-23 00019872 2

9 rows selected.

`temp` 公共表达式(CTE)查找了每个客户状态为1时的最高日期,而主查询返回了日期大于CTE返回的日期且状态为2的行

```sql
SQL> with temp as
  2    (select client_no, max(sym_run_date) sym_run_date
  3     from test
  4     where client_status = 1
  5     group by client_no
  6    )
  7  select a.client_no, min(a.sym_run_date) sym_run_date, a.client_status
  8  from test a join temp b on a.client_no = b.client_no
  9  where a.sym_run_date > b.sym_run_date
  10    and a.client_status = 2
  11  group by a.client_no, a.client_status;

CLIENT_N SYM_RUN_DA CLIENT_STATUS
-------- ---------- -------------
00019872 2023-03-28 2

SQL>
英文:

I don't particularly like this approach, but - at the moment, can't figure anything better.

Sample data:

SQL&gt; select * From test order by sym_run_date desc;

SYM_RUN_DA CLIENT_N CLIENT_STATUS
---------- -------- -------------
2023-03-31 00019872             2
2023-03-30 00019872             2
2023-03-29 00019872             2
2023-03-28 00019872             2
2023-03-27 00019872             1
2023-03-26 00019872             1
2023-03-25 00019872             1
2023-03-24 00019872             2
2023-03-23 00019872             2

9 rows selected.

temp CTE finds the highest date per client for status = 1, while main query returns row whose date is larger than the one returned by the CTE, and whose status = 2.

SQL&gt; with temp as
  2    (select client_no, max(sym_run_date) sym_run_date
  3     from test
  4     where client_status = 1
  5     group by client_no
  6    )
  7  select a.client_no, min(a.sym_run_date) sym_run_date, a.client_status
  8  from test a join temp b on a.client_no = b.client_no
  9  where a.sym_run_date &gt; b.sym_run_date
 10    and a.client_status = 2
 11  group by a.client_no, a.client_status;

CLIENT_N SYM_RUN_DA CLIENT_STATUS
-------- ---------- -------------
00019872 2023-03-28             2

SQL&gt;

huangapple
  • 本文由 发表于 2023年6月5日 14:51:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76404080.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定