Oracle数据分摊问题解析

常会碰到由于业务需要,需要将某种汇总的数据按照一定的原则分摊给一堆数据。 其实,如果逻辑清晰的话,这类型的程序还是比较好些的。 本文重点是如果用简单的程序实现这种效果,而且不容易分摊分错。 所有的分摊问题,首先必须要搞清楚以下几点问题: 1

经常会碰到,由于业务需要,需要将某种汇总的数据按照一定的原则分摊给一堆数据。
其实,如果逻辑清晰的话,这类型的程序还是比较好些的。
本文重点是如果用简单的程序实现这种效果,而且不容易分摊分错。

所有的分摊问题,首先必须要搞清楚以下几点问题:
1 首要的,要确定 什么东西,多少数量 分摊给什么东西?举个形象的例子,一桶沙子分摊给一些瓶子。
2 分摊的先后原则。上面的例子,一桶沙子分摊给一些瓶子,那瓶子的被分摊顺序是什么样子的?沙子先给哪个瓶子?要先确定清楚。

说得好像有点麻烦,举个例子说明。
最近接到的一个需求:
PO入库的时候,批次可能重复输入,所以入库之后,库存已经汇总在一起了。然后用户对(汇总的)库存进行消耗(就是杂发)。
现在需要有个报表可以知道:按照先进先出的原则,区分用户的一段期间内的消耗数量 对应的是那笔入库单号。

备注:假设下面的数量对应都是主单位。

7.1 入库单R1  料号A 批次P1 接收入库 400
7.3 入库单R2  料号A 批次P1 接收入库 300
这时候,P1批次库存共 700
——-消耗(杂发)明细
7.10 消耗P1 100
7.12 消耗P1 200
8.10 消耗P1 200
8.13 消耗P1 100
8.20 消耗P1 50
9.20 消耗P1 50

如果查询报表的日期选择的是:8.1~8.31
     8.1号 之前共消耗100+200=300
8.1~8.31号 之内一共消耗:200+100+50=350

所以核心问题是要将350如何分摊在R1和R2里面。
要实现的分摊效果:
      入库总数      之前消耗的分摊    期间内消耗的分摊
R1       400           300                  100
R2       300            0                   250

所以,结果是,报表是:8.1~8.31
一共消耗350,对应入库单的消耗情况:
R1消耗100
R2消耗250

实现逻辑:
你可以假想,现在有2个沙桶,
红色的沙桶装的沙子是 之前消耗的分摊 的数量
黑色的沙桶装的沙子是 期间内消耗的分摊 的数量
每张入库单就是一个瓶子,所以共有2个瓶子,R1和R2。现在是如何将 红色的沙子 和 黑色的沙子 装到这2个瓶子里面。

装沙规则:
1 用沙子的顺序:先用 红色的沙子,用完之后,再用黑色的沙子。
2 装瓶子的顺序:按照先进先出的原则,必须先装瓶子R1,再装R2.

DECLARE
  L_PRE_PERIOD_QTY NUMBER; —期间前的汇总消耗量 —之前消耗的分摊 的数量—红色的沙子
  L_CURR_PERIOD_QTY NUMBER ; –本期的汇总消耗量–期间内消耗的分摊 的数量—黑色的沙子
  —-装的结果用记录类型存下来,因为后面要用到。
   TYPE shipment_consume_Rec_Type   IS RECORD
   (
     SHIPMENT_LINE_ID  NUMBER
   , PRIMARY_QUANTITY             NUMBER
   , consume_pre_qty NUMBER
   , consume_curr_qty NUMBER
      );
    TYPE shipment_consume_Tbl_Type IS TABLE OF shipment_consume_Rec_Type
    INDEX BY BINARY_INTEGER ;
    L_shipment_consume_Tbl shipment_consume_Tbl_Type;
    N NUMBER;
BEGIN
  —-1 首先要算出红色的沙子和黑色的沙子的总数量,就是有多少数量可分摊。
SELECT nvl(sum(case when MMT.transaction_date      ABS(NVL(MTLN.PRIMARY_QUANTITY,0))
     else
       0
     end ),0) PRE_PERIOD_QTY,
     nvl(sum(case when MMT.transaction_date >= :P_F_START_DATE then
     ABS(NVL(MTLN.PRIMARY_QUANTITY,0))
     else
       0
     end ),0) CURR_PERIOD_QTY
   INTO L_PRE_PERIOD_QTY,L_CURR_PERIOD_QTY
  FROM MTL_MATERIAL_TRANSACTIONS MMT
      ,MTL_TRANSACTION_LOT_NUMBERS MTLN
WHERE MMT.TRANSACTION_ID = MTLN.TRANSACTION_ID
   AND MMT.TRANSACTION_TYPE_ID = 74
   AND MMT.TRANSACTION_ACTION_ID = 6
   AND MMT.OWNING_TP_TYPE = 1 —所有权转出的(寄售供应商的库存)
   —
   AND MMT.ORGANIZATION_ID = 103
   AND MMT.INVENTORY_ITEM_ID = 11783561
   AND MTLN.LOT_NUMBER = ‘P0000001’
   AND MMT.transaction_date   DBMS_OUTPUT.PUT_LINE(‘L_PRE_PERIOD_QTY:’||L_PRE_PERIOD_QTY||’ -L_CURR_PERIOD_QTY:’||L_CURR_PERIOD_QTY);
   N := 1;

   —–2 分摊主逻辑。
   FOR REC_SHIPMENT_LINE IN (
       —–瓶子(入库单)的游标
    SELECT MMT.ORGANIZATION_ID
        ,MMT.INVENTORY_ITEM_ID
        ,MTLN.LOT_NUMBER
        ,MTLN.TRANSACTION_DATE
        ,RT.SHIPMENT_HEADER_ID
        ,RT.SHIPMENT_LINE_ID
        ,MTLN.PRIMARY_QUANTITY
    FROM MTL_TRANSACTION_LOT_NUMBERS MTLN, MTL_MATERIAL_TRANSACTIONS MMT,RCV_TRANSACTIONS RT
   WHERE MTLN.TRANSACTION_ID = MMT.TRANSACTION_ID
     AND RT.TRANSACTION_ID = MMT.RCV_TRANSACTION_ID
     AND MMT.TRANSACTION_TYPE_ID = 18
     AND MMT.TRANSACTION_SOURCE_TYPE_ID = 1
     AND XYG_PO_PKG.CHECK_PO_LINE_CONSIGN(RT.PO_LINE_ID) = ‘Y’
     AND MMT.ORGANIZATION_ID = 103
     AND MMT.INVENTORY_ITEM_ID = 11783561
     AND MTLN.LOT_NUMBER = ‘P0000001’
     ORDER BY MTLN.TRANSACTION_DATE,MMT.TRANSACTION_ID) LOOP
       —2.1 优先消耗期初之前的耗料数量,就是先用红色的沙子的数量。
       IF L_PRE_PERIOD_QTY >= REC_SHIPMENT_LINE.PRIMARY_QUANTITY THEN —当红色沙子的数量大于瓶子的容量的时候。
         L_shipment_consume_Tbl(N).SHIPMENT_LINE_ID :=REC_SHIPMENT_LINE.SHIPMENT_LINE_ID;
         L_shipment_consume_Tbl(N).PRIMARY_QUANTITY :=REC_SHIPMENT_LINE.PRIMARY_QUANTITY;
         —-消耗红沙的数量就是瓶子的容量。
         L_shipment_consume_Tbl(N).consume_pre_qty :=REC_SHIPMENT_LINE.PRIMARY_QUANTITY;
         L_shipment_consume_Tbl(N).consume_curr_qty :=0;
         —-期初数量就是剩下要分配的数量。因为红色沙子已经被消耗掉一部分了。
         L_PRE_PERIOD_QTY :=L_PRE_PERIOD_QTY-REC_SHIPMENT_LINE.PRIMARY_QUANTITY;
       ELSE —当红色沙子的数量小于瓶子容量的时候
         L_shipment_consume_Tbl(N).SHIPMENT_LINE_ID :=REC_SHIPMENT_LINE.SHIPMENT_LINE_ID;
         L_shipment_consume_Tbl(N).PRIMARY_QUANTITY :=REC_SHIPMENT_LINE.PRIMARY_QUANTITY;
         —-瓶子装 红色沙子的数量就是红色沙子的数量了
         L_shipment_consume_Tbl(N).consume_pre_qty :=L_PRE_PERIOD_QTY;

         —-这时候已经用完红色沙子了,开始用黑色沙子了—–
           —2.2 当黑色沙子数量大于瓶子 可用的容量 的时候。
         IF L_CURR_PERIOD_QTY > (REC_SHIPMENT_LINE.PRIMARY_QUANTITY – L_PRE_PERIOD_QTY) THEN
           —该瓶子 装黑色沙子的数量 就是 瓶子的可用容量。
           L_shipment_consume_Tbl(N).consume_curr_qty := REC_SHIPMENT_LINE.PRIMARY_QUANTITY – L_PRE_PERIOD_QTY;
           —本次还有多少数量需要被下一个单号分摊,就是确定剩下还有多少黑色沙子可用。
           L_CURR_PERIOD_QTY := L_CURR_PERIOD_QTY – L_shipment_consume_Tbl(N).consume_curr_qty;
         ELSE
           —-当黑色沙子数量 小于或者等于 瓶子的可用容量的时候
           —–该瓶子装黑色沙子的数量就是 瓶子的可用容量。
           L_shipment_consume_Tbl(N).consume_curr_qty := L_CURR_PERIOD_QTY;
           —–黑色沙子用完咯!~~一定要赋值0,因为根据黑色沙子的使用情况判断后面是否要退出瓶子的循环。
           L_CURR_PERIOD_QTY := 0;
         END IF;
         L_PRE_PERIOD_QTY:= 0;
       END IF;
        N := N+1;
        —-当黑色沙子用完的时候,要退出循环。因为沙子数量可能很少,但是瓶子很多。。。没必要再循环下去了。
        IF L_CURR_PERIOD_QTY          EXIT;
        END IF;
     END LOOP;
    
     —显示装的结果。
     FOR I IN 1..L_shipment_consume_Tbl.COUNT LOOP
      DBMS_OUTPUT.PUT_LINE(L_shipment_consume_Tbl(I).SHIPMENT_LINE_ID
      ||’-‘|| L_shipment_consume_Tbl(I).PRIMARY_QUANTITY
      ||’-‘|| L_shipment_consume_Tbl(I).consume_pre_qty
      ||’-‘|| L_shipment_consume_Tbl(I).consume_curr_qty
      );
     
     END LOOP;
END;

/*
—例如:
L_PRE_PERIOD_QTY:0 -L_CURR_PERIOD_QTY:2020.2
18467366-1605.5-0-1605.5
18633076-5014.7-0-414.7

*/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1082838.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
双十一年度游戏盛宴,折扣、福利与精彩活动嗨翻全场!
上一篇 2025年12月2日 19:59:21
前端挑战:冬至
下一篇 2025年12月2日 19:59:30

相关推荐

  • VSCode的代码怎么运行_VSCode多语言代码执行方法与配置教程

    VSCode通过调用系统已安装的语言运行时来运行代码,需先安装对应语言环境,再结合扩展、集成终端或配置文件实现执行。 VSCode运行代码,说白了,它自己其实不“运行”代码,它更像是一个极其智能的遥控器和指挥中心。它利用你系统里已经安装好的各种语言运行时、编译器或解释器来完成这个任务。核心思路就是:…

    2026年9月2日
    200
  • Oracle树结构中如何高效统计每个节点的子节点数量?

    高效统计Oracle树结构中每个节点的子节点数量 在Oracle数据库中,统计树形结构每个节点的子节点数量,通常采用递归查询或连接查询。本文提供两种方法,并比较其效率。 方法一:递归查询 (Recursive Query) 此方法利用Oracle的递归查询特性,逐层遍历树结构,计算每个节点的子节点数…

    2026年9月2日
    200
  • Oracle树结构查询:如何递归查询指定节点下子节点数量?

    Oracle数据库树结构递归查询子节点数量详解 本文介绍如何在Oracle数据库中使用递归查询高效地统计树状结构中指定节点下的所有子节点数量。 核心方法:递归查询 Oracle数据库支持递归查询,允许查询语句自身调用,从而遍历整个树形结构。 SQL语句: 以下SQL语句实现递归查询,统计每个节点的子…

    2026年9月2日
    100
  • java学习应用篇|windows安装JDK及配置环境变量

    java学习应用篇|windows安装JDK及配置环境变量java学习应用篇|windows安装JDK及配置环境变量java学习应用篇|windows安装JDK及配置环境变量java学习应用篇|windows安装JDK及配置环境变量

    学习前言 实际上,本系统中最有价值的内容已经在前两篇文章中介绍完毕,接下来的内容主要是对前面知识的应用。新知识层出不穷,每隔几天就会有新的概念和框架出现。我们在本系列学习中,力求通过基本的学习方法来深入探究代码的本质,这样无论将来出现什么新的知识点,我们都能迅速学习并应用。小刀的水平有限,欢迎大家在…

    2026年9月1日 用户投稿
    200
  • Java.lang.VerifyError: Bad type on operand stack 错误是如何产生的以及如何解决?

    Java.lang.VerifyError: Bad type on operand stack 错误详解及解决方案 此错误通常源于Java虚拟机(JVM)的字节码验证器检测到操作数栈上的数据类型与目标方法预期类型不符。这意味着JVM无法验证方法的正确性,从而拒绝执行。 错误信息解读: 例如,错误信…

    2026年9月1日
    000
  • oracle中fetch的用法是什么

    oracle中,fetch用于限制查询返回的行数,可指定在行限制开始之前要跳过行数,若跳过则偏移量为0,行限制从第一行开始计算,语法为“[OFFSET offset ROWS]FETCH NEXT ROWS[ONLY|WITH TES]”。 本教程操作环境:Windows10系统、Oracle 11…

    2026年9月1日
    000
  • Mybatis-Plus如何配置Oracle表空间并解决字段大小写问题?

    MyBatis-Plus连接Oracle数据库:表空间与大小写配置详解 使用MyBatis-Plus操作Oracle数据库时,常常会遇到表空间指定和字段大小写问题。本文将详细介绍如何解决这两个常见问题。 问题一:指定Oracle表空间 MyBatis-Plus默认从当前用户默认表空间读取数据。若要指…

    2026年9月1日
    100
  • stimulsoft oracle,Stimulsoft Reports

    stimulsoft oracle,Stimulsoft Reportsstimulsoft oracle,Stimulsoft Reportsstimulsoft oracle,Stimulsoft Reportsstimulsoft oracle,Stimulsoft Reports

    大家好,很高兴再次与大家见面,我是你们的老朋友全栈君。 Stimulsoft Reports 一站式报表解决方案,支持 .NET、JavaScript、Java 和 PHP。 软件商:Stimulsoft 当前版本:2020.3 发布日期:2020/6/12 推荐: 以下是“Reports.Web”…

    2026年8月31日 用户投稿
    1500
  • 什么是oracle序列

    在oracle中,序列是用于产生一系列唯一数字的数据库对象;序列也就是一个序列号生成器,可以为表中的行自动生成序列号,主要的用途是生成主键的值,并且定义序列的用户必须具有CREATE SEQUENCE权限。 本教程操作环境:Windows10系统、Oracle 11g版、Dell G3电脑。 什么是…

    2026年8月31日
    000
  • laravel框架支持的几种数据库系统

    Laravel框架支持MySQL、PostgreSQL、MariaDB、SQL Server、SQLite和Oracle Database等数据库系统。选择数据库系统取决于特定应用程序的规模、性能、特性、成本和支持需求。 Laravel 框架支持的数据库系统 Laravel 是一个 PHP Web …

    2026年8月30日
    100
  • 如何高效迁移20亿条Oracle数据到新数据库?

    挑战:6小时内迁移20亿条Oracle数据 将20亿条Oracle数据迁移至新数据库,如何在6小时内完成单省份、单物资类型的处理?这是一个复杂的数据迁移难题,本文提供一种基于Java多线程的解决方案,并探讨异常处理和效率优化策略。 问题分析: 需要将Oracle数据库A表中的20亿条记录迁移到B表。…

    2026年8月30日
    000
  • Java程序如何高效迁移20亿条Oracle数据库数据并实现断点续传?

    Java程序高效迁移20亿条Oracle数据库数据,并实现断点续传 面对从Oracle数据库A表迁移20亿条数据到数据库B表的挑战,如何在6小时内完成单省份单物资类型的处理至关重要。本文探讨基于Java的解决方案,重点关注高效数据处理和断点续传机制,确保数据迁移的快速性和准确性。 目标是将A表(包含…

    2026年8月30日
    000
  • Java程序如何高效迁移20亿Oracle数据库数据?

    Java程序优化策略:6小时内迁移20亿Oracle数据库数据 面对20亿条Oracle数据库数据的迁移难题,如何在6小时内完成单省份单物资类型的处理?本文提供一种基于Java的多线程优化方案,旨在高效、准确地将数据迁移至新数据库B表。此方案特别适用于数据模型差异巨大、需复杂计算且仅能读取源数据(A…

    2026年8月30日
    000
  • mysql与oracle有区别吗

    mysql与oracle有区别:1、Oracle是一个对象关系数据库管理系统(ORDBMS),而MySQL是一个关系数据库管理系统(RDBMS);2、Oracle是闭源的(收费),MySQL是开源的(免费);3、Oracle是大型数据库,而MySQL是中小型数据库;4、Oracle可设置用户权限、访…

    2026年8月30日
    100
  • MySQL存储过程调试流程详解_Sublime插件支持语法结构高亮检查

    MySQL存储过程调试流程详解_Sublime插件支持语法结构高亮检查MySQL存储过程调试流程详解_Sublime插件支持语法结构高亮检查MySQL存储过程调试流程详解_Sublime插件支持语法结构高亮检查MySQL存储过程调试流程详解_Sublime插件支持语法结构高亮检查

    mysql存储过程调试困难,核心解决策略包括:1.利用select语句输出变量值;2.写入日志表记录执行状态;3.使用signal抛出错误中断流程;4.sublime text辅助代码检查。由于mysql缺乏原生调试器,通常通过运行时输出信息观察程序状态,如在关键逻辑插入select查看变量、将调试…

    2026年8月30日 用户投稿
    100
  • win11升级后软件不兼容怎么办_win11升级后软件兼容性处理方法

    首先使用兼容性疑难解答工具检测并修复问题,若无效则尝试手动设置兼容模式、以管理员身份运行、更新软件或启用.NET Framework等系统组件,最后可考虑虚拟机或替代软件方案。 如果您在将系统升级到 Windows 11 后发现某些软件无法正常运行,这通常是因为新系统的架构或安全策略与旧版软件存在冲…

    2026年8月28日
    100
  • VSCode怎么写JAVA项目_VSCode创建与开发Java项目完整教程

    答案是:配置VSCode写Java需三步——装JDK、配环境变量、装Java扩展包;创建项目用命令面板选Maven/Gradle;通过设置JDK路径、代码格式化、调内存提升效率;常见问题如语言服务器失败可清缓存或重启解决;依赖管理靠pom.xml或build.gradle,VSCode侧边栏提供Ma…

    2026年8月28日
    500
  • Oracle字符集检查和修改

    在部署oracle数据库重构版测试环境时,若未正确设置数据库字符集,可能导致后续脚本执行中文乱码。最终解决方案是清除所有数据,修改字符集,并重启数据库。 1、Oracle字符集概述 系统或程序运行的环境通常称为locale。设置数据库locale的最简单方法是通过设置NLS_LANG环境参数。在Li…

    2026年8月28日
    100
  • oracle数据库超大表名更改,oracle如何修改表名_数据库,oracle,修改表名[通俗易懂]

    大家好,很高兴再次与你们见面,我是全栈君。 Oracle数据库中建表的语法是什么?让我们来看看。 Oracle建表的语句是CREATE TABLE tablename(column_name datatype)。这里的tablename是您想要创建的表名,column_name是字段名称,而data…

    2026年8月28日
    100
  • linux安装oracle乱码

    方案:安装oracle中jre字体库的中文字体 1、下载字体文件 2、进入 database/stage/Components/oracle.jdk/1.6.0.75.0/1/DataFiles/目录 12c环境下,此文件夹下有 filegroup1.jar filegroup2.jar fileg…

    2026年8月28日
    300

发表回复

登录后才能评论
关注微信