发票连号判断-两种实现方式

两种方式找出连号发票

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 是因为能算大数

若有错误,希望大佬指出。
对你有帮助给点个👍再走呗。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值