From d7966922a5d913926ad98af0dfbbcd24bf510005 Mon Sep 17 00:00:00 2001 From: "han\\hanst" Date: Fri, 28 Nov 2025 17:31:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=94=AF=E6=8C=81=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/ecss/entity/EcssCoDelNotify.java | 6 + .../ecss/service/impl/CoDelServiceImpl.java | 319 +++++++++++++----- .../resources/mapper/ecss/CoDelMapper.xml | 43 +-- 3 files changed, 271 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/xujie/sys/modules/ecss/entity/EcssCoDelNotify.java b/src/main/java/com/xujie/sys/modules/ecss/entity/EcssCoDelNotify.java index ba794cdc..d9f02ed1 100644 --- a/src/main/java/com/xujie/sys/modules/ecss/entity/EcssCoDelNotify.java +++ b/src/main/java/com/xujie/sys/modules/ecss/entity/EcssCoDelNotify.java @@ -204,5 +204,11 @@ public class EcssCoDelNotify extends QueryPage { private String saleslt; private String manufacturerName; + + private String category; + + private String qtyRoll; + + private String qtyBox; } diff --git a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java index b6df2a21..2cf7d773 100644 --- a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java @@ -310,6 +310,89 @@ public class CoDelServiceImpl implements CoDelService { } + /** + * 安全获取字符串列值(支持可选列) + * 如果列不存在,返回空字符串 + * + * @param row 数据行 + * @param columnMap 列索引映射 + * @param columnName 列名 + * @return 单元格字符串值,如果列不存在返回空字符串 + */ + private String getStringCellValueSafe(XSSFRow row, Map columnMap, String columnName) { + Integer columnIndex = columnMap.get(columnName); + if (columnIndex == null) { + return ""; // 列不存在,返回空字符串 + } + return getStringCellValue(row, columnIndex); + } + + /** + * 安全获取数字列值(支持可选列) + * 如果列不存在,返回null + * + * @param row 数据行 + * @param columnMap 列索引映射 + * @param columnName 列名 + * @return 单元格数字值,如果列不存在返回null + */ + private BigDecimal getNumericCellValueSafe(XSSFRow row, Map columnMap, String columnName) { + Integer columnIndex = columnMap.get(columnName); + if (columnIndex == null) { + return null; // 列不存在,返回null + } + return getNumericCellValueOrDefault(row, columnIndex); + } + + /** + * 解析Excel第一行,建立列名到列索引的映射关系 + * + * @param headerRow 第一行(表头行) + * @return 列名到列索引的映射Map + */ + private Map parseExcelHeader(XSSFRow headerRow) { + Map columnIndexMap = new HashMap<>(); + if (headerRow == null) { + throw new RuntimeException("Excel表头行不能为空!"); + } + + // 遍历第一行的所有单元格,建立列名到索引的映射 + int lastCellNum = headerRow.getLastCellNum(); + for (int i = 0; i < lastCellNum; i++) { + String columnName = getStringCellValue(headerRow, i); + if (StringUtils.isNotBlank(columnName)) { + // 去除空格并统一格式 + columnName = columnName.trim(); + columnIndexMap.put(columnName, i); + } + } + + // 验证必填列是否存在(根据代码中的验证逻辑确定) + String[] requiredColumns = { + "PO#", // 必填 + "PN", // 必填 + "Qty (pcs)", // 必填 + "Cargo Ready Date", // 必填 + "Destination", // 必填 + "Shipping Mode", // 必填 + "Currency", // 必填 + "TP" // 必填 + }; + + List missingColumns = new ArrayList<>(); + for (String column : requiredColumns) { + if (!columnIndexMap.containsKey(column)) { + missingColumns.add(column); + } + } + + if (!missingColumns.isEmpty()) { + throw new RuntimeException("Excel表头缺少必填列: " + String.join(", ", missingColumns)); + } + + return columnIndexMap; + } + private void importNotifyExcel(EcssCoDelNotifyHeaderData inData, XSSFWorkbook workbook, String site, SysUserEntity currentUser, List excelList) { for (int s = 0; s < workbook.getNumberOfSheets(); s++) { @@ -319,74 +402,159 @@ public class CoDelServiceImpl implements CoDelService { deleteEmptyRow(sheet); // 获取行数 int rows = sheet.getPhysicalNumberOfRows(); - // 遍历每一行(从第二行开始) - for (int j = 1; j < rows; j++) { - // 创建对象 - EcssCoDelNotifyData task = new EcssCoDelNotifyData(); - XSSFRow row0 = sheet.getRow(0); - if (row0.getCell(0) == null || StringUtils.isBlank(getStringCellValue(row0, 0)) - || !getStringCellValue(row0, 0).equals("Ready Date")) { - continue; - } + + if (rows < 4) { + continue; // 至少需要前2行、表头行(第3行)和一行数据(第4行) + } + + // 获取第三行(表头行) + XSSFRow headerRow = sheet.getRow(2); + + // 验证第一列第3行必须是"PO Rec. Date"且不能为空 + if (headerRow == null || headerRow.getCell(0) == null + || StringUtils.isBlank(getStringCellValue(headerRow, 0)) + || !getStringCellValue(headerRow, 0).trim().equals("PO Rec. Date")) { + log.warn("Sheet {} 的第一列第3行不是 'PO Rec. Date' 或为空,跳过该Sheet", sheet.getSheetName()); + continue; // 跳过该Sheet + } + + // 解析表头行(第3行),获取列索引映射 + Map columnMap = parseExcelHeader(headerRow); + + // 遍历每一行(从第四行开始,即索引3) + for (int j = 3; j < rows; j++) { // 获得该行 XSSFRow row = sheet.getRow(j); - if (row==null) { + if (row == null) { continue; } - if (row.getCell(13) == null || StringUtils.isBlank(getStringCellValue(row, 13))) { + + // 检查第一列,如果没有值或者值是空字符串则跳过该行 + if (row.getCell(0).getCellType() == CellType.BLANK || row.getCell(0).getCellType() == CellType.ERROR + || row.getCell(0) == null || StringUtils.isBlank(getStringCellValue(row, 0))) { + log.debug("第{}行第一列为空,跳过该行", j+1); continue; } - if (row.getCell(18) != null && getStringCellValue(row, 18).equals("内销")) { + + // 跳过内销数据(如果"内外销方式"列存在) + Integer saleTypeIdx = columnMap.get("内外销方式"); + if (saleTypeIdx != null && row.getCell(saleTypeIdx) != null + && getStringCellValue(row, saleTypeIdx).equals("内销")) { continue; } - if (row.getCell(0) == null ) { - throw new RuntimeException("第" + (j+1) + "行的Ready Date不能为空!"); + + // 必填字段验证 + Integer cargoReadyDateIdx = columnMap.get("Cargo Ready Date"); + if (row.getCell(cargoReadyDateIdx) == null) { + throw new RuntimeException("第" + (j+1) + "行的Cargo Ready Date不能为空!"); } - if (row.getCell(1) == null) { + + Integer poIdx = columnMap.get("PO#"); + if (row.getCell(poIdx) == null) { throw new RuntimeException("第" + (j+1) + "行的PO#不能为空!"); } - if (row.getCell(8) == null) { + + Integer pnIdx = columnMap.get("PN"); + if (row.getCell(pnIdx) == null) { throw new RuntimeException("第" + (j+1) + "行的PN不能为空!"); } - if (row.getCell(11) == null) { + + Integer qtyIdx = columnMap.get("Qty (pcs)"); + if (row.getCell(qtyIdx) == null) { throw new RuntimeException("第" + (j+1) + "行的Qty不能为空!"); } - if (row.getCell(13) == null) { - throw new RuntimeException("第" + (j+1) + "行的CMC Invoice不能为空!"); - } - if (row.getCell(15) == null) { + + Integer destinationIdx = columnMap.get("Destination"); + if (row.getCell(destinationIdx) == null) { throw new RuntimeException("第" + (j+1) + "行的Destination不能为空!"); } - if (row.getCell(17) == null) { + + Integer shippingModeIdx = columnMap.get("Shipping Mode"); + if (row.getCell(shippingModeIdx) == null) { throw new RuntimeException("第" + (j+1) + "行的Shipping Mode不能为空!"); } - if (row.getCell(21) == null) { + + Integer currencyIdx = columnMap.get("Currency"); + if (row.getCell(currencyIdx) == null) { throw new RuntimeException("第" + (j+1) + "行的Currency不能为空!"); } - if (row.getCell(22) == null) { + + Integer tpIdx = columnMap.get("TP"); + if (row.getCell(tpIdx) == null) { throw new RuntimeException("第" + (j+1) + "行的TP不能为空!"); } - // 为对象赋值 + + // 创建对象并为对象赋值 + EcssCoDelNotifyData task = new EcssCoDelNotifyData(); task.setSite(site); // site task.setBuNo(inData.getBuNo()); // bu + + // 解析日期 Date readDate; try { - //String date = getStringCellValue(row, 0); - LocalDate localDate = parseDateCell(row.getCell(0)); + LocalDate localDate = parseDateCell(row.getCell(cargoReadyDateIdx)); String formatted = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); readDate = DateUtils.getDateByParten(formatted, "yyyy-MM-dd"); } catch (ParseException e) { throw new RuntimeException("第" + (j+1) + "行的ReadyDate格式有误!"); } task.setReadyDate(readDate); - task.setCustomerPO(getStringCellValue(row, 1)); - task.setSalesOrder(getStringCellValue(row, 4)); - task.setLine(getStringCellValue(row, 2)); - task.setVersion(getStringCellValue(row, 3)); - task.setSaleslt(getStringCellValue(row, 5)); - task.setStatus(getStringCellValue(row, 6)); - task.setFamily(getStringCellValue(row, 7)); - task.setPn(getStringCellValue(row, 8)); + + // 使用动态索引读取数据(必填列) + task.setCustomerPO(getStringCellValue(row, poIdx)); + task.setPn(getStringCellValue(row, pnIdx)); + task.setQty(getNumericCellValueOrDefault(row, qtyIdx)); + task.setDestination(getStringCellValue(row, destinationIdx)); + task.setShippingMode(getStringCellValue(row, shippingModeIdx)); + task.setCurrency(getStringCellValue(row, currencyIdx)); + task.setTp(getNumericCellValueOrDefault(row, tpIdx)); + + // 处理CMC Invoice:如果CMC Invoice为空则取Shipping Number,如果两者都为空则报错 + String cmcInvoiceValue = getStringCellValueSafe(row, columnMap, "CMC Invoice"); + String shippingNumberValue = getStringCellValueSafe(row, columnMap, "Shipping Number"); + + if (StringUtils.isBlank(cmcInvoiceValue) && StringUtils.isBlank(shippingNumberValue)) { + throw new RuntimeException("第" + (j+1) + "行的CMC Invoice和Shipping Number不能同时为空!"); + } + + // 如果CMC Invoice为空,则使用Shipping Number + if (StringUtils.isBlank(cmcInvoiceValue)) { + task.setCmcInvoice(shippingNumberValue); + } else { + task.setCmcInvoice(cmcInvoiceValue); + } + task.setShippingNumber(shippingNumberValue); + + // 读取可选列(列不存在时返回空值或null) + task.setSalesOrder(getStringCellValueSafe(row, columnMap, "Sales Order")); + task.setLine(getStringCellValueSafe(row, columnMap, "Line#")); + task.setVersion(getStringCellValueSafe(row, columnMap, "Version#")); + task.setSaleslt(getStringCellValueSafe(row, columnMap, "Saleslt")); + task.setStatus(getStringCellValueSafe(row, columnMap, "Status")); + task.setFamily(getStringCellValueSafe(row, columnMap, "Family")); + task.setPartDescription(getStringCellValueSafe(row, columnMap, "Description")); + task.setManufacturerName(getStringCellValueSafe(row, columnMap, "Manufacturer Name")); + task.setCmcComment(getStringCellValueSafe(row, columnMap, "CMC Comment")); + task.setAwbBl(getStringCellValueSafe(row, columnMap, "AWB/ BL#")); + task.setForwarderInfo(getStringCellValueSafe(row, columnMap, "Forwarder Info")); + task.setSo(getStringCellValueSafe(row, columnMap, "SO")); + task.setUpc(getStringCellValueSafe(row, columnMap, "UPC")); + task.setRemark(getStringCellValueSafe(row, columnMap, "备注")); + task.setCategory(getStringCellValueSafe(row, columnMap, "Category")); + task.setQtyRoll(getStringCellValueSafe(row, columnMap, "QTY/ROLL")); + task.setQtyBox(getStringCellValueSafe(row, columnMap, "qty/box")); + task.setSaleType(getStringCellValueSafe(row, columnMap, "内外销方式")); // 内外销 + + task.setLt(getNumericCellValueSafe(row, columnMap, "LT (wks)")); + task.setTtlAmount(getNumericCellValueSafe(row, columnMap, "TTL Amount")); + task.setVat(getNumericCellValueSafe(row, columnMap, "VAT")); + task.setSumPrice(getNumericCellValueSafe(row, columnMap, "价税合计")); // 价税合计 + task.setRoll(getNumericCellValueSafe(row, columnMap, "Roll")); + + BigDecimal carton = getNumericCellValueSafe(row, columnMap, "BOX"); + task.setCarton(carton != null ? carton.setScale(1, RoundingMode.HALF_UP) : null); + + // 查询物料信息 List parts = coDelMapper.getPartNo(site, task.getPn(), currentUser.getUsername(), inData.getBuNo()); if (parts.isEmpty()) { // 物料不存在时,设置 partNo 为 pn,后续会在批量检查阶段被筛选掉 @@ -394,34 +562,14 @@ public class CoDelServiceImpl implements CoDelService { } else { task.setPartNo(parts.get(0).getPartNo()); } - task.setPartDescription(getStringCellValue(row, 9)); - task.setManufacturerName(getStringCellValue(row, 10)); - task.setQty(getNumericCellValueOrDefault(row, 11)); - if (task.getQty().compareTo(BigDecimal.ZERO)==0) { + + if (task.getQty().compareTo(BigDecimal.ZERO) == 0) { task.setStatus("取消发货"); } - task.setLt(getNumericCellValueOrDefault(row, 12)); - task.setCmcInvoice(getStringCellValue(row, 13)); - task.setCmcComment(getStringCellValue(row, 14)); - task.setDestination(getStringCellValue(row, 15)); - task.setSaleType(getStringCellValue(row, 18)); - task.setAwbBl(getStringCellValue(row, 19)); - task.setShippingNumber(getStringCellValue(row, 16)); - task.setShippingMode(getStringCellValue(row, 17)); - task.setForwarderInfo(getStringCellValue(row, 20)); - task.setCurrency(getStringCellValue(row, 21)); - task.setTp(getNumericCellValueOrDefault(row, 22)); - task.setTtlAmount(getNumericCellValueOrDefault(row, 23)); - task.setVat(getNumericCellValueOrDefault(row, 24)); - task.setSumPrice(getNumericCellValueOrDefault(row, 25)); - task.setSo(getStringCellValue(row, 26)); - task.setUpc(getStringCellValue(row, 27)); - task.setRemark(getStringCellValue(row, 28)); - task.setRoll(getNumericCellValueOrDefault(row, 29)); - task.setCarton(getNumericCellValueOrDefault(row, 30)!=null? Objects.requireNonNull(getNumericCellValueOrDefault(row, 30)).setScale(1, RoundingMode.HALF_UP):null); task.setErpFlag("N"); task.setNotifyStatus("已计划"); task.setUsername(inData.getUsername()); + // 物料存在性检查已移至批量处理阶段,此处不再单独检查 excelList.add(task); } @@ -813,37 +961,48 @@ public class CoDelServiceImpl implements CoDelService { // 先删除全部明细,再新建明细 coDelMapper.deleteAllEcssDelDetail(headerData); - // 构建原数据Map,使用itemNo作为唯一标识 - // 注意:不能用pn作为key,因为同一个pn可能有多行记录,每行都需要独立比较 - Map originalDataMap = dbData.stream() - .collect(Collectors.toMap(EcssCoDelNotifyDetail::getItemNo, detail -> detail, (v1, v2) -> v1)); + // 智能判断改单逻辑:按PN分组汇总数量,避免因顺序变化导致误判 + // 构建原数据Map:按PN分组,计算每个PN的总数量 + Map originalPnQtyMap = new HashMap<>(); + for (EcssCoDelNotifyDetailData detail : dbData) { + String pn = detail.getPn(); + BigDecimal qty = detail.getQty(); + originalPnQtyMap.put(pn, originalPnQtyMap.getOrDefault(pn, BigDecimal.ZERO).add(qty)); + } + // 构建新数据Map:按PN分组,计算每个PN的总数量 + Map newPnQtyMap = new HashMap<>(); + for (EcssCoDelNotifyData excelData : excelList) { + String pn = excelData.getPn(); + BigDecimal qty = excelData.getQty(); + newPnQtyMap.put(pn, newPnQtyMap.getOrDefault(pn, BigDecimal.ZERO).add(qty)); + } + + // 设置itemNo并判断每一行是否有变化(智能判断:按PN比较总数量) for (int i = 0; i < excelList.size(); i++) { excelList.get(i).setDelNo(headerData.getDelNo()); excelList.get(i).setItemNo(i + 1); - // 判断数据是否变化:按itemNo匹配原数据,对比PN和数量 - Integer itemNo = i + 1; - EcssCoDelNotifyDetailData originalDetail = originalDataMap.get(itemNo); + String pn = excelList.get(i).getPn(); + BigDecimal originalTotalQty = originalPnQtyMap.get(pn); + BigDecimal newTotalQty = newPnQtyMap.get(pn); - // 判断是否有修改(包括新增、换料、数量变更) + // 判断是否有修改(按PN比较总数量,避免因顺序变化误判) boolean isModified = false; boolean isQtyModified = false; - if (originalDetail == null) { - // 新增行:原数据中不存在该itemNo + if (originalTotalQty == null) { + // 新增PN:原数据中不存在该PN isModified = true; isQtyModified = true; - } else if (!originalDetail.getPn().equals(excelList.get(i).getPn())) { - // 换料:PN不同 - isModified = true; - isQtyModified = true; - } else if (!originalDetail.getQty().equals(excelList.get(i).getQty())) { - // 数量变更:PN相同但数量不同 + log.info("检测到新增PN: {}, 数量: {}", pn, newTotalQty); + } else if (originalTotalQty.compareTo(newTotalQty) != 0) { + // 数量变更:PN存在但总数量不同 isModified = true; isQtyModified = true; + log.info("检测到PN数量变更: {}, 原数量: {}, 新数量: {}", pn, originalTotalQty, newTotalQty); } - // 其他情况:PN和数量都相同,无变化,isModified保持false + // 其他情况:PN和总数量都相同,无变化,isModified保持false // 只有真正有变化的才标记modifyFlag=true excelList.get(i).setModifyFlag(isModified); @@ -853,6 +1012,13 @@ public class CoDelServiceImpl implements CoDelService { excelList.get(i).setModifyQtyFlag(true); } } + + // 检查是否有PN被删除(在原数据中存在但新数据中不存在) + for (String originalPn : originalPnQtyMap.keySet()) { + if (!newPnQtyMap.containsKey(originalPn)) { + log.info("检测到PN被删除: {}, 原数量: {}", originalPn, originalPnQtyMap.get(originalPn)); + } + } coDelMapper.batchSaveEcssCoDelNotifyDetail(excelList); headerData.setModifyFlag(true); // 更新头表字段,包括ReadyDate、ShippingMode、Destination @@ -3586,7 +3752,8 @@ public class CoDelServiceImpl implements CoDelService { } private static void deleteEmptyRow(XSSFSheet sheet) { - for (int i = 0; i <= sheet.getLastRowNum(); i++) { + // 从第三行开始遍历,检查每一行是否为空 + for (int i = 2; i <= sheet.getLastRowNum(); i++) { XSSFRow row = sheet.getRow(i); boolean isEmptyRow = true; if (row != null) { diff --git a/src/main/resources/mapper/ecss/CoDelMapper.xml b/src/main/resources/mapper/ecss/CoDelMapper.xml index 6fd2615a..34f447bc 100644 --- a/src/main/resources/mapper/ecss/CoDelMapper.xml +++ b/src/main/resources/mapper/ecss/CoDelMapper.xml @@ -176,13 +176,14 @@ insert into ecss_CoDelNotifyDetail (site,bu_no,delNo,item_no,salesOrder,salesOrder_item_no,customerPO,line,version, status,family,part_no,part_description,qty,lt,cmc_comment,saleType, awb_bl,shipping_number,forwarder_info,currency,tp,ttl_amount,sum_price, - so,upc,remark,pn,surplus_qty,vat,roll,carton,saleslt,manufacturer_name,modifyFlag,modifyQtyFlag) + so,upc,remark,pn,surplus_qty,vat,roll,carton,saleslt,manufacturer_name,modifyFlag,modifyQtyFlag,category,qty_roll,qty_box) values (#{item.site},#{item.buNo},#{item.delNo},#{item.itemNo,jdbcType=INTEGER},#{item.salesOrder,jdbcType=NVARCHAR},#{item.salesOrderItemNo},#{item.customerPO,jdbcType=NVARCHAR},#{item.line,jdbcType=NVARCHAR},#{item.version,jdbcType=NVARCHAR}, #{item.status,jdbcType=NVARCHAR},#{item.family,jdbcType=NVARCHAR},#{item.partNo},#{item.partDescription,jdbcType=NVARCHAR},#{item.qty,jdbcType=DECIMAL},#{item.lt,jdbcType=DECIMAL},#{item.cmcComment,jdbcType=NVARCHAR},#{item.saleType,jdbcType=NVARCHAR}, #{item.awbBl,jdbcType=NVARCHAR},#{item.shippingNumber,jdbcType=NVARCHAR},#{item.forwarderInfo,jdbcType=NVARCHAR},#{item.currency,jdbcType=NVARCHAR},#{item.tp,jdbcType=DECIMAL},#{item.ttlAmount,jdbcType=DECIMAL},#{item.sumPrice,jdbcType=DECIMAL}, - #{item.so,jdbcType=NVARCHAR},#{item.upc,jdbcType=NVARCHAR},#{item.remark,jdbcType=NVARCHAR},#{item.pn,jdbcType=NVARCHAR},#{item.qty},#{item.vat},#{item.roll},#{item.carton},#{item.saleslt,jdbcType=NVARCHAR},#{item.manufacturerName,jdbcType=NVARCHAR},#{item.modifyFlag},#{item.modifyQtyFlag}) + #{item.so,jdbcType=NVARCHAR},#{item.upc,jdbcType=NVARCHAR},#{item.remark,jdbcType=NVARCHAR},#{item.pn,jdbcType=NVARCHAR},#{item.qty},#{item.vat},#{item.roll},#{item.carton},#{item.saleslt,jdbcType=NVARCHAR},#{item.manufacturerName,jdbcType=NVARCHAR}, + #{item.modifyFlag},#{item.modifyQtyFlag},#{item.category,jdbcType=NVARCHAR},#{item.qtyRoll,jdbcType=NVARCHAR},#{item.qtyBox,jdbcType=NVARCHAR}) @@ -216,11 +217,11 @@ - update ecss_CoDelNotifyHeader + update ecss_CoDelNotifyHeader set modifyFlag=#{modifyFlag}, - modify_count = CASE - WHEN #{modifyFlag} = 1 THEN ISNULL(modify_count, 0) + 1 - ELSE 0 + modify_count = CASE + WHEN #{modifyFlag} = 1 THEN ISNULL(modify_count, 0) + 1 + ELSE 0 END where site=#{site} and delNo=#{delNo} @@ -851,7 +852,7 @@ left join ecss_CoDelNotifyHeader noHeader on a.site=noHeader.site and a.delNo=no -- 修复净重毛重重复计算问题:按数量比例分配箱子重量 WITH BoxDetail AS ( - SELECT + SELECT b.pn, b.qty, b.rolls, @@ -900,16 +901,16 @@ left join ecss_CoDelNotifyHeader noHeader on a.site=noHeader.site and a.delNo=no b.delNo, b.seq_no, -- 计算该零件数量占该箱子总数量的比例 - CASE - WHEN SUM(b.qty) OVER (PARTITION BY b.site, b.bu_no, b.delNo, b.seq_no) > 0 + CASE + WHEN SUM(b.qty) OVER (PARTITION BY b.site, b.bu_no, b.delNo, b.seq_no) > 0 THEN b.qty * 1.0 / SUM(b.qty) OVER (PARTITION BY b.site, b.bu_no, b.delNo, b.seq_no) ELSE 0 END as qtyRatio - FROM ecss_CoDelBoxList a + FROM ecss_CoDelBoxList a LEFT JOIN ecss_CoDelPalletDetail b ON a.site=b.site AND a.bu_no=b.bu_no AND a.delNo=b.delNo AND a.item_no=b.seq_no WHERE a.site=#{site} AND a.bu_no=#{buNo} AND a.delNo=#{delNo} ) - SELECT + SELECT pn, CONVERT(DECIMAL(20, 0), SUM(qty)) as total_qty, CONVERT(DECIMAL(20, 0), SUM(DISTINCT box_qty)) as box_qty, @@ -927,7 +928,7 @@ left join ecss_CoDelNotifyHeader noHeader on a.site=noHeader.site and a.delNo=no