【问题标题】:Populating an entire column with same value returned from a CASE statement使用从 CASE 语句返回的相同值填充整个列
【发布时间】:2018-12-28 14:26:53
【问题描述】:

我正在尝试通过整个 s_date/part_no 分组,从结果 CASE 语句中填充具有相同结果值的列。

我们已经尝试了多种不同的路线来让递归来满足我们的需要,但都没有成功。计算非常棘手,而且我们知道 SQL 不是递归的最佳选择,因此我们正在尝试寻找替代路线,暂时满足客户需求和时间紧迫。

SELECT
        s_date,
        part_no,
        i_group,
        s_level,
        p_category,
        qty_filled,
        qty_total,
        relief_amt,
        extreme_amt,
        curr_mth_note,
        CASE
            WHEN curr_mth_note IS NOT NULL
                 AND i_group = '1'
                 AND s_level = '80' THEN qty_filled
            ELSE NULL
        END AS g1s1_filled
        FROM
        (
            SELECT
                t1.s_date,
                t1.part_no,
                t1.i_group,
                t1.s_level,
                t1.p_category,
                t1.qty_filled,
                t1.qty_total,
                mv.relief_amt,
                mv.extreme_amt,
                mv.curr_mth_note,
            FROM
                multi_table mv,
                t_table t1
            WHERE
                t1.part_no = mv.part_no
                AND mv.part_no = 'xxxx'
                AND t1.s_date = mv.s_date
                AND t1.s_date = '201805'
            GROUP BY
                t1.s_date,
                t1.i_group,
                t1.s_level,
                t1.part_no,
                t1.p_category,
                t1.qty_filled,
                t1.qty_total,
                mv.relief_amt,
                mv.extreme_amt,
                mv.curr_mth_note,
            ORDER BY
                t1.s_date,
                t1.i_group,
                t1.s_level DESC
        )
ORDER BY
    s_date,
    part_no,
    i_group,
    DECODE(s_level, '80', 1, '100', 2, 'Late', 3)

上面的当前输出如下所示:

我正在尝试/希望得到的是整个 g1s1_filled 列显示相同的 67 数量,其中 i_group = '1' and s_level = '80' 用于所有可用的日期/部分组合。

所以要让该列显示:

G1S1_FILLED
67
67
67
67
67

我研究了如何尝试使用 where 而不是 when,但没有运气。 还会有多个像这样构建的其他列,我最终也可以在其中进行计算。

【问题讨论】:

  • 在您的示例数据中,只有一条记录满足i_group = '1's_level = '80' 的条件,g1s_filled 的值为 67。所以我很难看到问题。
  • @RyanWilson 是的,我知道,但我将为每个 i_group / s_level 组合进行单独计算,这必须基于之前的总数,具体取决于relief_amt 列中剩余的内容。因此,我尝试垂直填充相同的值,以便让这些计算按预期工作。
  • 如果s_date/part_no 组合有多个 1/80 行怎么办 - 您将如何选择要使用的 qty_filled 值中的哪一个? (或者这四列是否形成一个复合键,这样就不会发生?)
  • @AlexPoole 这不会发生,因为日期/部分/组/级别组合数量已经在其他视图中计算,并被拉入此处,因此我们可以将它们单独用于报告.

标签: sql oracle case


【解决方案1】:

我想你想要一个窗口函数:

    SUM(CASE WHEN curr_mth_note IS NOT NULL AND i_group = '1' AND
                  s_level = '80'
             THEN qty_filled
        END) OVER (PARTITION BY s_date, part_no)  AS g1s1_filled

【讨论】:

  • 非常感谢...这很好用!我能够建立计算并得到我希望的结果。我讨厌答案看起来如此简单,我觉得我已经绞尽脑汁好几个小时了。再次感谢!
【解决方案2】:

您可以在SELECT 子句中使用条件分析最小值。我没有你的数据,所以我将在SCOTT.EMP 表上用类似的查询来说明——假设我想用一位特定员工的薪水填充NEWCOL。我会这样做:

select empno, ename, sal, job, deptno,
       min(case when empno = 7499 and ename = 'ALLEN' then sal end) over () as newcol
from   scott.emp;

     EMPNO ENAME             SAL JOB           DEPTNO     NEWCOL
---------- ---------- ---------- --------- ---------- ----------
      7369 SMITH             800 CLERK             20       1600
      7499 ALLEN            1600 SALESMAN          30       1600
      7521 WARD             1250 SALESMAN          30       1600
      7566 JONES            2975 MANAGER           20       1600
      7654 MARTIN           1250 SALESMAN          30       1600
      7698 BLAKE            2850 MANAGER           30       1600
      7782 CLARK            2450 MANAGER           10       1600
      7788 SCOTT            3000 ANALYST           20       1600
      7839 KING             5000 PRESIDENT         10       1600
      7844 TURNER           1500 SALESMAN          30       1600
      7876 ADAMS            1100 CLERK             20       1600
      7900 JAMES             950 CLERK             30       1600
      7902 FORD             3000 ANALYST           20       1600
      7934 MILLER           1300 CLERK             10       1600

如果(在您的问题中)只有一行具有 I_GROUPS_LEVEL 中的“特殊”值组合,那么您可以使用(条件、分析)MINMAX 甚至 @ 987654329@ 或 SUM - 它们都将等于单个值,在您的情况下为 67。如果有多个这样的值,那么您将需要做出选择:您想要MINMAXAVG,还是其他的。无论如何,您仍然可以使用相同的想法。

【讨论】:

    【解决方案3】:

    代替case语句,为它写一个子查询

    (select qty_filled 
      from t_Table 
      where 
        i_group = '1' and 
        s_level = '80' and
        rownum = 1 
    ) as g1s1_filled
    

    【讨论】:

    • 这只会返回所有列中值为 1 的列。
    • 我不确定你的表关系。你可以把你的关系约束放在哪里 caluse 这样它就会返回你需要的东西。
    【解决方案4】:

    您可以删除 CASE 表达式并将整个查询(ORDER BY 子句除外)移动到 CTE。然后,您可以自行JOIN 将相关的g1s1_filled 附加到每一行。

    注意:定义自连接条件时必须小心;我在下面提供了一个建议,您可能需要对其进行改进。

    查询:

    WITH cte AS (
        SELECT
            s_date,
            part_no,
            i_group,
            s_level,
            p_category,
            qty_filled,
            qty_total,
            relief_amt,
            extreme_amt,
            curr_mth_note
            FROM
            (
                SELECT
                    t1.s_date,
                    t1.part_no,
                    t1.i_group,
                    t1.s_level,
                    t1.p_category,
                    t1.qty_filled,
                    t1.qty_total,
                    mv.relief_amt,
                    mv.extreme_amt,
                    mv.curr_mth_note,
                FROM
                    multi_table mv,
                    t_table t1
                WHERE
                    t1.part_no = mv.part_no
                    AND mv.part_no = 'xxxx'
                    AND t1.s_date = mv.s_date
                    AND t1.s_date = '201805'
                GROUP BY
                    t1.s_date,
                    t1.i_group,
                    t1.s_level,
                    t1.part_no,
                    t1.p_category,
                    t1.qty_filled,
                    t1.qty_total,
                    mv.relief_amt,
                    mv.extreme_amt,
                    mv.curr_mth_note,
                ORDER BY
                    t1.s_date,
                    t1.i_group,
                    t1.s_level DESC
            )
    )
    SELECT a.*, b.qty_filled as g1s1_filled
    FROM 
        cte AS a
        INNER JOIN cte as b 
            ON  b.s_date = a.s_date 
            AND b.part_no = a.part_no 
            AND b.i_group = '1' 
            AND b.s_level = '80'
            AND b.curr_mth_note IS NOT NULL
    ORDER BY
        a.s_date,
        a.part_no,
        a.i_group,
        DECODE(a.s_level, '80', 1, '100', 2, 'Late', 3)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-03
      • 2020-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多