2017-05-08 140 views
0

我已经跨一个奇怪的要求,我需要计算的数据库查询运行计算出来SQL查询滞后运行计算

我有一个表 表A:

Day  QTY 
0  NULL  
1  1  
2  1  
3  0  
4  0  
5  2  
6  1  
7  1  
8  3  

使用这个表,我需要计算其他列

Day QTY  Op_Qty CL_QTY Reqd  Need Adjust 
0 0  null  3 -   -  - 
1 1  3   2 -   -  - 
2 1  2   1 Reqd  3  - 
3 0  1   1 Reqd  3  - 
4 0  1   4    0  3 
5 2  4   5    0  3 
6 1  5   4    0  0 
7 1  4   3    0  0 
8 3  3   0 Reqd  4  0 

Logic : 
CL_Qty starting value is 3 2nd row onwards its op_qty-qty+adjust 
op_qty = previous record of cl_qty 
reqd --> will start after 2 records and computation formula = if cl_qty is less than 2 then "reqd" else empty string 
need --> will start after 2 records and computation formula = if reqd column value = "reqd" then (4- cl_qty) else 0 
adjust --> will start after 4th record = 1st value of need 

我试图使用lag但无处关闭结果。它将对任何输入有很大的帮助

+0

提供SQL – SaggingRufus

+0

显示迄今为止尝试的内容。 –

+0

需求中出现问题。 “你会在第四张唱片后开始”是什么意思?也许你的意思是前三行有0,但你显示NULL。这意味着对于第2,3,4行,CL_Qty的结果将为NULL。请澄清。 – mathguy

回答

0

正如mathguy指出的那样,递归类将允许这样做内联。因为在这里没有,如果你的情况允许使用pl/sql (我无法从你的帖子中知道),或许值得考虑放入pl/sql并程序化地评估数据集。

它可能仍然是可能的,而不诉诸于pl/sql但没有递归子因子,属性之间的混合行内和行间关系似乎不太可能。这不太好,但是这里有一个例子,在你的文章中用一个函数生成你期望的输出。

有在这个例子中的一些注意事项:

  • 甲骨文不承认空字符串,如您表示应该 出现在REQD时不'reqd'。我在这里使用了NULL
  • 由于ADJUST的值用于计算CL_QTY,NULL无效。对于前四条记录,CL_QTY使用0 的固定ADJUST而不是显示的NULL。我建议明确使用0 代替ADJUST的前四个值,而不是NULL
  • 我不知道这里是什么在 要求,即“需要1个值”的意思 -“调整>会后需要4纪录= 1的值 开始”。在这个例子中,我把它意味着“是尚未在ADJUST使用 NEED的最后一个值(2条)之前,”
  • 本示例假设行级条件应是确定和排序由DAY 。如果排序顺序不同,则需要更新光标。

有了这样说,这里是你介绍的是使用function一个方法,你可以用它来复制所需的数据表的例子:

首先创建测试数据:

CREATE TABLE DAY_QUANTITY(
    DAY NUMBER, 
    QTY NUMBER 
); 

INSERT INTO DAY_QUANTITY VALUES (0,NULL); 
INSERT INTO DAY_QUANTITY VALUES (1,1); 
INSERT INTO DAY_QUANTITY VALUES (2,1); 
INSERT INTO DAY_QUANTITY VALUES (3,0); 
INSERT INTO DAY_QUANTITY VALUES (4,0); 
INSERT INTO DAY_QUANTITY VALUES (5,2); 
INSERT INTO DAY_QUANTITY VALUES (6,1); 
INSERT INTO DAY_QUANTITY VALUES (7,1); 
INSERT INTO DAY_QUANTITY VALUES (8,3); 

然后TYPE返回:

CREATE OR REPLACE TYPE QTY_ADJUST_REC IS OBJECT(DAY NUMBER, QTY NUMBER, OP_QTY NUMBER, CL_QTY NUMBER, REQD VARCHAR2(10), NEED NUMBER, ADJUST NUMBER); 
/

CREATE OR REPLACE TYPE QTY_ADJUST_TAB IS TABLE OF QTY_ADJUST_REC; 
/

而且FUNCTION。这将通过数据迭代和应用规则,因为他们成为合格:

CREATE OR REPLACE FUNCTION QTY_ADJUST 
    RETURN QTY_ADJUST_TAB 
IS 
    V_ITERATION_COUNT NUMBER := 0; 
    V_CL_QTY   NUMBER := 3; 
    V_NEED   NUMBER := NULL; 
    V_OP_QTY   NUMBER := NULL; 
    V_REQD   VARCHAR2(10) := NULL; 
    V_ADJUST   NUMBER := NULL; 

    V_QTY_ADJUST_REC QTY_ADJUST_REC; 
    V_QTY_ADJUST_TAB QTY_ADJUST_TAB; 
    BEGIN 
    V_QTY_ADJUST_TAB := QTY_ADJUST_TAB(); 

    FOR POINTER IN (SELECT 
         DAY, 
         QTY 
        FROM DAY_QUANTITY 
        ORDER BY DAY ASC) 
    LOOP 
     V_ITERATION_COUNT := V_ITERATION_COUNT + 1; 

     IF V_QTY_ADJUST_TAB.COUNT() > 0 
     THEN 
     V_OP_QTY := V_QTY_ADJUST_TAB(V_QTY_ADJUST_TAB.COUNT()).CL_QTY; 
     V_CL_QTY := (V_QTY_ADJUST_TAB(V_QTY_ADJUST_TAB.COUNT()).CL_QTY 
        - POINTER.QTY 
        + CASE WHEN V_ITERATION_COUNT < 5 THEN 0 ELSE 
      COALESCE(V_QTY_ADJUST_TAB(V_QTY_ADJUST_TAB.COUNT() - 1).NEED, 0) END); 
     END IF; 

     IF V_ITERATION_COUNT > 2 
     THEN 
     V_REQD := CASE WHEN V_CL_QTY < 2 
      THEN 'reqd' 
        ELSE NULL END; 
     V_NEED := CASE WHEN V_CL_QTY < 2 
      THEN (4 - V_CL_QTY) 
        ELSE 0 END; 
     END IF; 
     IF V_ITERATION_COUNT > 4 
     THEN 
     V_ADJUST := V_QTY_ADJUST_TAB(V_QTY_ADJUST_TAB.COUNT() - 1).NEED; 
     END IF; 
     V_QTY_ADJUST_REC := QTY_ADJUST_REC(POINTER.DAY, POINTER.QTY, V_OP_QTY, V_CL_QTY, V_REQD, V_NEED, V_ADJUST); 

     V_QTY_ADJUST_TAB.EXTEND(); 
     V_QTY_ADJUST_TAB(V_QTY_ADJUST_TAB.COUNT()) := V_QTY_ADJUST_REC; 

     V_CL_QTY := NULL; 
     V_REQD := NULL; 
     V_NEED := NULL; 
     V_ADJUST := NULL; 

    END LOOP; 

    RETURN V_QTY_ADJUST_TAB; 

    END; 
/

Function QTY_ADJUST compiled 

然后对其进行测试:

SELECT * FROM TABLE(QTY_ADJUST()) ORDER BY 1 ASC; 

DAY QTY OP_QTY CL_QTY REQD NEED ADJUST 
0     3       
1 1 3  2       
2 1 2  1  reqd 3    
3 0 1  1  reqd 3    
4 0 1  4    0  3  
5 2 4  5    0  3  
6 1 5  4    0  0  
7 1 4  3    0  0  
8 3 3  0  reqd 4  0  

编辑:在回答你的要求提供额外subfactoring解决方案,这里是一个替代例如使用递归CTE。
这与上述过程方法在机械上类似 - 它以迭代方式构建结果集 - 但是使用SQL来代替。

这个例子可以做一些重构,但希望给出一个递归子因子可以工作的一种方法的例子(请注意,还有其他方式来生成这种类型的数据,以及使用这种类型的查询)。

使用从上述PL/SQL例子相同DAY_QUANTITY表和数据,这里的子因素的一个例子采用同样的处理,以将数据:

WITH NUMBERED_DAY_QTY(DAY, QTY, NUMBERED_ROW) AS (
    SELECT 
    DAY_QUANTITY.DAY, 
    DAY_QUANTITY.QTY, 
    ROW_NUMBER() 
    OVER (
     PARTITION BY NULL 
     ORDER BY DAY_QUANTITY.DAY ASC) - 1 AS NUMBERED_ROW 
    FROM DAY_QUANTITY), 
    DAY_QTY_ITER(DAY, QTY, NUMBERED_ROW, OP_QTY, CL_QTY, REQD, NEED, ADJUST, NEED_POINTER, ITERATION_LEVEL) 
    AS (
    SELECT 
     DAY, 
     QTY, 
     NUMBERED_ROW, 
     CAST(NULL AS NUMBER) AS OP_QTY, 
     3     AS CL_QTY, 
     NULL     AS REQD, 
     CAST(NULL AS NUMBER) AS NEED, 
     CAST(NULL AS NUMBER) AS ADJUST, 
     CAST(NULL AS NUMBER) AS NEED_POINTER, 
     1     AS ITERATION_LEVEL 
    FROM NUMBERED_DAY_QTY 
    WHERE DAY = 0 
    UNION ALL 
    SELECT 
     NUMBERED_DAY_QTY.DAY, 
     NUMBERED_DAY_QTY.QTY, 
     NUMBERED_DAY_QTY.NUMBERED_ROW, 
     DAY_QTY_ITER.CL_QTY        AS OP_QTY, 
     (DAY_QTY_ITER.CL_QTY - NUMBERED_DAY_QTY.QTY + 
     CASE WHEN DAY_QTY_ITER.ITERATION_LEVEL < 4 
     THEN 0 
     ELSE COALESCE(DAY_QTY_ITER.NEED_POINTER, 0) END) AS CL_QTY, 
     CASE WHEN DAY_QTY_ITER.ITERATION_LEVEL < 2 
     THEN NULL 
     ELSE CASE WHEN (DAY_QTY_ITER.CL_QTY - NUMBERED_DAY_QTY.QTY + 
         CASE WHEN DAY_QTY_ITER.ITERATION_LEVEL < 4 
         THEN 0 
         ELSE COALESCE(DAY_QTY_ITER.NEED_POINTER, 0) END) < 2 
     THEN 'reqd' 
      ELSE NULL END END       AS REQD, 
     CASE WHEN DAY_QTY_ITER.ITERATION_LEVEL < 2 
     THEN NULL 
     ELSE CASE WHEN (DAY_QTY_ITER.CL_QTY - NUMBERED_DAY_QTY.QTY + 
         CASE WHEN DAY_QTY_ITER.ITERATION_LEVEL < 4 
         THEN 0 
         ELSE COALESCE(DAY_QTY_ITER.NEED_POINTER, 0) END) < 2 
     THEN (4 - (DAY_QTY_ITER.CL_QTY - NUMBERED_DAY_QTY.QTY + 
        CASE WHEN DAY_QTY_ITER.ITERATION_LEVEL < 4 
        THEN 0 
        ELSE COALESCE(DAY_QTY_ITER.NEED_POINTER, 0) END)) 
      ELSE 0 END END       AS NEED, 
     CASE WHEN DAY_QTY_ITER.ITERATION_LEVEL < 4 
     THEN NULL 
     ELSE 
     COALESCE(DAY_QTY_ITER.NEED_POINTER, 0) END  AS ADJUST, 
     DAY_QTY_ITER.NEED         AS NEED_POINTER, 
     DAY_QTY_ITER.ITERATION_LEVEL + 1     AS ITERATION_LEVEL 
    FROM NUMBERED_DAY_QTY 
     INNER JOIN DAY_QTY_ITER ON NUMBERED_DAY_QTY.NUMBERED_ROW = DAY_QTY_ITER.ITERATION_LEVEL) 
SELECT 
    DAY, QTY, OP_QTY, CL_QTY, REQD, NEED, ADJUST 
FROM DAY_QTY_ITER 
ORDER BY 1 ASC; 

然后对其进行测试:

DAY QTY OP_QTY CL_QTY REQD NEED ADJUST 
0     3       
1 1 3  2       
2 1 2  1  reqd 3    
3 0 1  1  reqd 3    
4 0 1  4    0  3  
5 2 4  5    0  3  
6 1 5  4    0  0  
7 1 4  3    0  0  
8 3 3  0  reqd 4  0  


9 rows selected. 
+0

感谢您的创新解决方案,如何使用11.2中的递归执行 – luminita

+0

感谢@luminita,您希望看到一个SQL替代方案吗?当然。我离开了我的办公桌,但当我回到办公桌时,我会举一个例子。我会在更新发布后跟进。谢谢 – alexgibbs

+0

@luminita我添加了另一个使用子因子的例子,只在sql中应用相同的规则。这是你希望看到的那种东西吗?谢谢 – alexgibbs