两种方式找出连号发票
1. 需求
在做票据夹功能的时候,有一个功能叫查找这个单据中所有连号的发票。换个角度说是:给定一个自然数集合,求这个自然数集合中包含多少个自然数串。这么想就简单了,可以使用两种方法实现:
方法1 : 使用sql, 一条sql语句查询出所有连号的发票,本人使用的是mysql8+;
方法2: 使用java,也就是把所有的发票号码查出来,通过写java代码来实现这个功能;
方法3: 使用js ,其实跟java一样,就不再写了;
众所周知:发票连号只判断增值税票和出租车票,下面的我就不再写条件了
2. 方法1 SQL
SELECT
grp AS diff,
COUNT(*) AS countNum,
GROUP_CONCAT( INVOICE_CODE ORDER BY INVOICE_CODE ) AS invoiceCodes,
INVOICE_TYPE AS invoiceType
FROM
( SELECT INVOICE_CODE, INVOICE_CODE - ROW_NUMBER() OVER ( ORDER BY INVOICE_CODE ) AS grp, INVOICE_TYPE FROM pbs_invoice_ocr pio ) cte
WHERE
grp IS NOT NULL
GROUP BY
grp
HAVING
COUNT(*) > 1
解析:
这里使用到了开窗函数,如果不了解的话,可以自行百度下,
ROW_NUMBER():是行号,从1开始计数
INVOICE_CODE:发票号
INVOICE_TYPE:发票类型‘
子查询 cte:
SELECT INVOICE_CODE, INVOICE_CODE - ROW_NUMBER() OVER ( ORDER BY INVOICE_CODE ) AS grp, INVOICE_TYPE FROM pbs_invoice_ocr pio ) cte
这句话的意思是:
-
ROW_NUMBER() OVER ( ORDER BY INVOICE_CODE ):根据 INVOICE_CODE
对记录进行排序,并为每个记录分配一个唯一的行号。 -
INVOICE_CODE - ROW_NUMBER():计算每个记录的 INVOICE_CODE 减去行号,作为分组依据。
grp:用于分组的字段。
例如: 发票号是:1 2 5 9 10
行号是:1 2 3 4 5
相减的结果是:0,0,2,5,5
结果显而易见: 1 2 9 10 是连号的发票
外部查询
相对就简单了 :
- HAVING COUNT(*) > 1:只保留分组记录数大于 1 的结果。
- GROUP BY grp:按 grp 分组。
3. 方法2 JAVA
这个就是纯算法了, debug 下就能看懂
/**
* 查找连续的自然数
*
* @param invoiceCodeList
* @return
*/
private List<List<String>> getConsecutiveNumberList(List<String> invoiceCodeList) {
// 判断是否连号
//收集的总的连续列表
List<List<String>> resultCon = new ArrayList<>();
//每个收集的连续临时列表
List<String> tempList = new ArrayList<>();
for (int i = 0; i < invoiceCodeList.size(); i++) {
String current = invoiceCodeList.get(i);
if (!isOnlyDigits(current.trim())) {
continue;
}
BigDecimal currentNum = new BigDecimal(current);
if (i < invoiceCodeList.size() - 1) {
String next = invoiceCodeList.get(i + 1);
if (!isOnlyDigits(next.trim())) {
continue;
}
BigDecimal nextNum = new BigDecimal(next);
if (nextNum.subtract(currentNum).compareTo(BigDecimal.ONE) == 0) {
// 连续
tempList.add(current);
} else {
// 不连续
// 不连续时,把最后一个数放进去之前的临时列表
tempList.add(current);
resultCon.add(tempList);
//同时把临时列表置空
tempList = new ArrayList<>();
}
} else {
//最后一个元素时,放入最后一个临时列表中
tempList.add(current);
resultCon.add(tempList);
}
}
return resultCon;
}
使用BigDecimal 是因为能算大数
若有错误,希望大佬指出。
对你有帮助给点个👍再走呗。