Oracle 嵌套 select 具有定义的行

Oracle nested select with defined rows

我的查询如下所示:

SELECT
    nvl(dd,'TOTAL') "Subject",
    SUM(cnt) "Count,
    SUM(pct) AS "%"
FROM
    (
SELECT
    dd,
    COUNT(1) cnt,
    round(RATIO_TO_REPORT(COUNT(1) ) OVER() * 100,2) AS pct
FROM
    student p,
    student_subject a
WHERE
    p.sId = a.sId
    AND student_type IN (
        '1',
        '2'
    )
    AND dd IN (
        'MATH',
        'SCIENCE',
        'HISTORY'
    )
    GROUP BY
    dd
ORDER BY
    1
)
GROUP BY
    ROLLUP(dd)
ORDER BY
    1;

我的输出应该是这样的:

Subject Count       %
MATH    33          23.2%
SCIENCE 24          11.46%
HISTORY 56          44.778%
TOTAL   113         85.4.2%

如果特定主题没有数据,它仍应为该行提供 0 值,如下所示

Subject Count       %
MATH    33          23.20%
SCIENCE 0           0.00%
HISTORY 56          44.77%
TOTAL   113         85.42%

我现在得到的是下面没有不需要的 SCIENCE 行,

Subject Count       %
MATH    33          23.20%
HISTORY 56          44.77%
TOTAL   113         85.42%

我所做的是删除了 dd IN 子句“AND dd IN ( 'MATH', 'SCIENCE', 'HISTORY' )" 但是我无法进入另一个内部 select 到 select 的 3 个主题。

您必须使用 case 语句使其为 0,如果任何主题为空,则将其默认为 0。如果您需要查询,请告诉我。我建议逻辑,以便您可以自己尝试。

如果我正确理解数据模型,当学生未注册某个科目时,该科目的条目将不会存在于 student_subject table 中,这意味着缺少的科目不存在于赤字 table 也是如此。因此,从技术上讲,不可能连接这两个 table 并报告其中任何一个都不存在的列值。 现在要解决这个问题,我使用 WITH 子句创建另一个 table 来保存所有需要的主题,并使用检索到的结果集执行外部连接。

我已经测试过了,效果很好。 table 和查询的完整解决方案(Oracle 18c)可以在 DBFIDDLE URL https://dbfiddle.uk/?rdbms=oracle_18&fiddle=df73453d7fa4e0478e74fa509b20a411 中找到。

  WITH some_data AS ( 
       SELECT 'MATH' AS subj
       FROM dual
       UNION ALL 
       SELECT 'SCIENCE' AS subj
       FROM dual
       UNION ALL
       SELECT 'HISTORY' AS subj
       FROM dual
    )
    SELECT
        nvl(subj,'TOTAL') "Subject",
        nvl(SUM(cnt),0) "Count",
        nvl(SUM(pct),0) AS "%"
    FROM
    (SELECT
        dd,
        COUNT(1) cnt,
        round(RATIO_TO_REPORT(COUNT(1) ) OVER() * 100,2) AS pct
    FROM
        student p,
        student_subject a
    WHERE
        p.sId = a.sId
        AND student_type IN (
            '1',
            '2'
        )
        AND dd IN (
            'MATH',
            'SCIENCE',
            'HISTORY'
        )
        GROUP BY
        dd
    ORDER BY
        1
    ) tab, some_data
    where tab.dd(+) = some_data.subj
    GROUP BY
        ROLLUP(subj)
    ORDER BY
        1;

您需要使用表列表作为 inner view 并使用 left join 如下:

SELECT NVL(DD, 'TOTAL') "Subject",
       SUM(CNT) "Count",
       SUM(PCT) AS "%"
FROM (
    SELECT DD,
           COUNT(1) CNT,
           ROUND(RATIO_TO_REPORT(COUNT(1)) OVER() * 100, 2) AS PCT
    FROM (
        SELECT 'MATH' AS SUB FROM DUAL UNION ALL
        SELECT 'SCIENCE' AS SUB FROM DUAL UNION ALL
        SELECT 'HISTORY' AS SUB FROM DUAL
    ) SUBJECTS
    LEFT JOIN STUDENT_SUBJECT A
    ON SUBJECTS.SUB = A.DD
    LEFT JOIN STUDENT P
    ON P.SID = A.SID
    WHERE STUDENT_TYPE IN (
        '1','2'
    )
    GROUP BY DD
    ORDER BY 1
)
GROUP BY ROLLUP(DD)
ORDER BY 1;