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
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_code
和doc_prefix
恢复前一个doc_number
的值,按doc_date
[=20排序=]
下一个子查询计算一个 window 定义记录组的总和。要比较 doc_number
s,我们只需将它们除以 10 并删除余数部分:当结果值不连续时,然后开始一个新组
最外层的查询只是在组内聚合
旁注:DATE
不是一个合理的列名,我在查询中将其重命名为 DOC_DATE
并且 fiddle.
我有以下数据
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
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_code
和doc_prefix
恢复前一个doc_number
的值,按doc_date
[=20排序=]下一个子查询计算一个 window 定义记录组的总和。要比较
doc_number
s,我们只需将它们除以 10 并删除余数部分:当结果值不连续时,然后开始一个新组最外层的查询只是在组内聚合
旁注:DATE
不是一个合理的列名,我在查询中将其重命名为 DOC_DATE
并且 fiddle.