Oracle:显示最小和最大连续代码但添加校验位

Oracle: show min and max consecutive code but adding check digit

我有以下数据

CUST_CODE DOC_PREFIX    DOC_NUMBER   DATE 
--------------------------------------------------
1111      001           1236         2019/01/01
1111      001           1249         2019/01/02
1111      001           1258         2019/01/03
1111      001           1268         2019/01/03
1111      002           1990         2019/02/15
1112      001           1118         2019/03/01
1112      003           1228         2019/03/01   
1112      003           1230         2019/03/01
1113      005           6666         2019/05/20
1114      002           6128         2019/10/01
1114      002           6138         2019/10/01
1114      002           6146         2019/10/01
1114      002           9916         2019/10/02
1114      002           9926         2019/10/02

DOC_NUMBER 是一个键码 + 一个校验位(第一个例子:123 是密码 6 是校验位)

我需要按 CUST_CODE 和 DOC_PREFIX 分组,仅显示连续数字中的 MIN 和 MAX DOC_NUMBER,但按代码排序,并显示 MIN 中的日期 DOC_NUMBER

这就是我需要的:

CUST_CODE DOC_PREFIX    MIN_DOC_NUMBER   MAX_DOC_NUMBER   DATE 
--------------------------------------------------------------------
1111      001           1236             1268             2019/01/01
1111      002           1990             1990             2019/02/15
1112      001           1118             1118             2019/03/01
1112      003           1128             1130             2019/03/01
1113      005           6666             6666             2019/05/20
1114      002           6128             6146             2019/10/01
1114      002           9916             9926             2019/10/02

如您所见,我的排序如下:

CUST_CODE : 1111  = 123(6),124(9),125(8),126(8)

为此我有下一个查询:

WITH DOCNUMS AS (
    SELECT 
        CUST_CODE,
        DOC_PREFIX,
        DATE,
        DOC_NUMBER AS DOC,
        TO_NUMBER(SUBSTR(DOC_NUMBER,1,LENGTH(DOC_NUMBER)-1)) AS DOC_NUMBER,
        TO_NUMBER(SUBSTR(DOC_NUMBER,1,LENGTH(DOC_NUMBER)-1)) - ROW_NUMBER()
    over(
        ORDER BY 
            TO_NUMBER(SUBSTR(DOC_NUMBER,1,LENGTH(DOC_NUMBER)-1))
        ) rn
    FROM 
        DOCS 
), ORDERDOCS AS (
    SELECT 
        DOCS.CUST_CODE,
        DOCS.DOC_PREFIX,
        MIN(DOCS.DOC_NUMBER) AS MIN_DOC,
        MAX(DOCS.DOC_NUMBER) AS MAX_DOC
    FROM 
        DOCNUMS DOCS
    GROUP BY    
        DOCS.CUST_CODE,DOCS.DOC_PREFIX,DOCS.rn
)   
    SELECT 
        DOCS.CUST_CODE,
        DOCS.DOC_PREFIX,
        DOCNUMS.DOC,
        (SELECT DOCNUMS.DOC FROM DOCNUMS WHERE DOCNUMS.CUST_CODE=DOCS.CUST_CODE AND DOCNUMS.DOC_NUMBER=DOCS.MAX_DOC),
        DOCNUMS.DATE
    FROM 
        ORDERDOCS DOCS
    INNER JOIN DOCNUMS
        ON DOCNUMS.CUST_CODE=DOCS.CUST_CODE
        AND DOCNUMS.DOC_NUMBER=DOCS.MIN_DOC

这行得通,但速度很慢,尤其是在下一部分

DOCNUMS.DOC,
(SELECT DOCNUMS.DOC FROM DOCNUMS WHERE DOCNUMS.CUST_CODE=DOCS.CUST_CODE AND DOCNUMS.DOC_NUMBER=DOCS.MAX_DOC)

如何从 doc_number 获取最小和最大代码,但显示带有校验位的 DOC_NUMBER?

这是一种空岛问题。这是用 window 总和解决它的一种方法:

select 
    cust_code, 
    doc_prefix, 
    min(doc_number) min_doc_number,
    max(doc_number) max_doc_number,
    min(doc_date) doc_date
from (
    select
        t.*,
        sum(case when floor(doc_number/10) = floor(lag_doc_number/10) + 1 then 0 else 1 end)
            over(partition by cust_code, doc_prefix order by doc_date) grp
    from (
        select
            t.*,
            lag(doc_number) 
                over(partition by cust_code, doc_prefix order by doc_date) lag_doc_number
        from mytable t
    ) t
) t
group by cust_code, doc_prefix, grp
order by cust_code, doc_prefix, grp

Demo on DB Fiddle:

CUST_CODE | DOC_PREFIX | MIN_DOC_NUMBER | MAX_DOC_NUMBER | DOC_DATE  
--------: | ---------: | -------------: | -------------: | :---------
     1111 |          1 |           1236 |           1268 | 2019/01/01
     1111 |          2 |           1990 |           1990 | 2019/02/15
     1112 |          1 |           1118 |           1118 | 2019/03/01
     1112 |          3 |           1228 |           1230 | 2019/03/01
     1113 |          5 |           6666 |           6666 | 2019/05/20
     1114 |          2 |           6128 |           6146 | 2019/10/01
     1114 |          2 |           9916 |           9926 | 2019/10/02

解释:

  • 最内层子查询对相同的cust_codedoc_prefix恢复前一个doc_number的值,按doc_date[=20排序=]

  • 下一个子查询计算一个 window 定义记录组的总和。要比较 doc_numbers,我们只需将它们除以 10 并删除余数部分:当结果值不连续时,然后开始一个新组

  • 最外层的查询只是在组内聚合

旁注:DATE 不是一个合理的列名,我在查询中将其重命名为 DOC_DATE 并且 fiddle.