【问题标题】:Replace two nested sub queries with one sub query or refactoring query with more appropriate query用一个子查询替换两个嵌套子查询或用更合适的查询重构查询
【发布时间】:2021-11-25 18:44:29
【问题描述】:

我有如下数据。这里我只显示数据,但实际上这些数据来自多个表。

CREATE TABLE project_complete_data (PROJECT_ID, PROJ_COMPANY_NAME,  PROJECT_NAME,           CUSTOM_LOT_NO,          TASK_NAME,                              TASK_ACTUAL_END_DATE,   TASK_FINISH_DATE,   TASK_FINISHED,  TASK_LAST_MODIFIED_DATE,    TASK_LAST_MODIFIED_DATE_TIME,                                       PO_TOTAL_AMOUNT ,   PO_STATUS,  PO_TYPE) AS
                        SELECT 511,         'A Inc.',           'A',                    '01a',                  'Rough-In Plumbing',                    DATE '2009-12-17',      DATE '2014-09-01',  1,              null,                       null,                                                               0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    '02',                   'Update Lender Info in BT - Sales Rep', DATE '2005-06-28',      DATE '2005-10-11',  1,              null,                       null,                                                               0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    '020',                  'TK task',                              DATE '2018-11-07',      DATE '2019-06-21',  1,              DATE '2019-06-21',          TO_DATE('2019-06-21 18:12:21', 'YYYY-MM-DD hh24:mi:ss'),            33,                 100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    '152',                  'HVAC rough',                           DATE '2021-09-16',      DATE '2021-08-05',  1,              DATE '2021-08-05',          TO_DATE('2021-08-05 18:40:05', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Bldg C1|Parcel 01&*',  'New task 1',                           DATE '2021-12-10',      DATE '2021-12-15',  0,              DATE '2021-12-10',          TO_DATE('2021-12-10 19:27:47', 'YYYY-MM-DD hh24:mi:ss'),            4,                  101,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Bldg C1|Parcel 01&*',  'New task 2',                           DATE '2021-12-12',      DATE '2021-12-16',  0,              DATE '2021-12-12',          TO_DATE('2021-12-12 19:27:47', 'YYYY-MM-DD hh24:mi:ss'),            5,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Bldg C1|Parcel 01&*',  'Install Countertops',                  DATE '2019-04-25',      DATE '2021-08-04',  1,              DATE '2021-08-04',          TO_DATE('2021-08-04 19:27:47', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Bldg C1|Parcel 01&*',  'Inspection: Backfill',                 DATE '2019-02-08',      DATE '2021-08-04',  1,              DATE '2021-08-04',          TO_DATE('2021-08-04 19:27:47', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Bldg C1|Parcel 01&*',  'Backfill',                             DATE '2019-02-11',      DATE '2019-06-10',  1,              DATE '2019-06-21',          TO_DATE('2019-06-21 20:47:51', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Bldg C1|Parcel 01&*',  'Set Foundation Walls',                 DATE '2019-02-01',      DATE '2019-02-01',  1,              DATE '2019-06-21',          TO_DATE('2019-06-21 18:22:23', 'YYYY-MM-DD hh24:mi:ss'),            0,                  101,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Bldg C1|Parcel 01&*',  'Dig and Form Footing',                 DATE '2019-01-24',      DATE '2019-01-23',  1,              DATE '2019-06-21',          TO_DATE('2019-06-21 18:21:29', 'YYYY-MM-DD hh24:mi:ss'),            5,                  101,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Bldg C1|Parcel 01&*',  'Pour Footing',                         DATE '2019-01-29',      DATE '2019-01-29',  1,              DATE '2019-06-21',          TO_DATE('2019-06-21 18:18:26', 'YYYY-MM-DD hh24:mi:ss'),            5,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Bldg C1|Parcel 01&*',  'Excavate Foundation',                  DATE '2019-01-22',      DATE '2019-01-22',  1,              DATE '2019-06-19',          TO_DATE('2019-06-19 18:15:44', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Bldg C1|Parcel 01&*',  'Stake out Foundation Lot',             DATE '2019-01-21',      DATE '2019-01-21',  1,              DATE '2019-06-19',          TO_DATE('2019-06-19 17:25:35', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Finalize Test 2',      'HVAC rough',                           DATE '2019-01-11',      DATE '2021-08-03',  1,              DATE '2021-08-03',          TO_DATE('2021-08-03 20:32:55', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Finalize Test 2',      'first floor framing',                  DATE '2018-11-30',      DATE '2018-11-26',  1,              DATE '2019-06-21',          TO_DATE('2019-06-21 23:24:28', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Finalize Test 2',      'second floor framing',                 DATE '2018-12-07',      DATE '2018-10-29',  1,              DATE '2019-06-21',          TO_DATE('2019-06-21 23:18:38', 'YYYY-MM-DD hh24:mi:ss'),            0,                  101,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Lot # 4',              'Excavate Foundation',                  DATE '2018-11-02',      DATE '2018-11-05',  1,              DATE '2019-06-21',          TO_DATE('2019-06-21 18:28:51', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Lot # 8',              'New task 1',                           DATE '2021-12-08',      DATE '2021-12-11',  0,              DATE '2021-12-08',          TO_DATE('2021-12-08 20:42:54', 'YYYY-MM-DD hh24:mi:ss'),            6,                  101,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Lot # 8',              'New task 2',                           DATE '2021-12-09',      DATE '2021-12-12',  0,              DATE '2021-12-09',          TO_DATE('2021-12-09 20:42:56', 'YYYY-MM-DD hh24:mi:ss'),            12,                 100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Lot # 8',              'electrical rough',                     DATE '2019-08-15',      DATE '2021-08-03',  1,              DATE '2021-08-03',          TO_DATE('2021-08-03 20:42:54', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Lot # 8',              'HVAC rough',                           DATE '2019-08-27',      DATE '2021-08-03',  1,              DATE '2021-08-03',          TO_DATE('2021-08-03 20:42:54', 'YYYY-MM-DD hh24:mi:ss'),            12,                 100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Lot # 8',              'first floor framing',                  DATE '2019-08-22',      DATE '2021-07-19',  1,              DATE '2021-07-19',          TO_DATE('2021-07-19 15:52:38', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Lot # 8',              'first floor framing',                  DATE '2019-08-22',      DATE '2021-07-19',  1,              DATE '2021-07-19',          TO_DATE('2021-07-19 15:52:38', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Lot # 8',              'second floor framing',                 DATE '2019-09-03',      DATE '2019-06-17',  1,              DATE '2019-06-20',          TO_DATE('2019-06-20 20:41:04', 'YYYY-MM-DD hh24:mi:ss'),            0,                  100,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'Orange Star',          'cabinet-task',                         DATE '2018-04-02',      DATE '2018-05-15',  1,              DATE '2018-05-15',          TO_DATE('2018-05-15 15:12:03', 'YYYY-MM-DD hh24:mi:ss'),            0,                  101,        100 FROM DUAL
              UNION ALL SELECT 511,         'A Inc.',           'A',                    'A test lot',           'first floor framing',                  DATE '2021-05-28',      DATE '2021-07-30',  1,              DATE '2021-07-30',          TO_DATE('2021-07-30 19:03:21', 'YYYY-MM-DD hh24:mi:ss'),            0,                  101,        100 FROM DUAL
              UNION ALL SELECT 3247,        'B Inc.',           'B',                    '01/002.B',             'first floor framing',                  DATE '2021-07-30',      DATE '2021-09-20',  1,              DATE '2021-09-20',          TO_DATE('2021-09-20 16:19:53', 'YYYY-MM-DD hh24:mi:ss'),            0,                  101,        100 FROM DUAL;

现在我必须得到最后完成的任务。我还需要根据所有相同批次的某些条件sum po_total_amount。然后计算百分比。最后用这些总和和百分比显示最后修改的任务。

我想出了以下嵌套查询

Select project_name,
custom_lot_no as "Lot#",
task_name AS "Last Completed Task with a PO",
task_actual_end_date as "Task Actual End Date",
TOTAL_POS_COMPLETED as "Total POs Completed",
TOTAL_COMMITED as "Total Committed",
Round(NVL((TOTAL_POS_COMPLETED / NULLIF(TOTAL_COMMITED, 0)) ,0) * 100) || '%' AS "% Completed"
from(
    select project_id, 
        project_name,
        custom_lot_no,
        task_name,
        task_actual_end_date,
        SUM(pos_completed) OVER (PARTITION BY custom_lot_no, TASK_FINISHED) AS TOTAL_POS_COMPLETED,
        SUM(committed) OVER (PARTITION BY custom_lot_no, TASK_FINISHED) AS TOTAL_COMMITED,
        last_modified_date_time,
        last_task_finish_seq
    from (
        select 
            project_id,
            proj_company_name,
            project_name,       
            custom_lot_no, 
            task_name,
            NVL(to_char(task_actual_end_date), ' ') AS TASK_ACTUAL_END_DATE,
            task_finish_date AS TASK_FINISH_DATE,
            task_finished AS TASK_FINISHED,
            to_char(task_last_modified_date_time, 'YYYY-MM-DD hh24:mi:ss') as last_modified_date_time,
            ROW_NUMBER() OVER (PARTITION BY custom_lot_no, task_finished ORDER BY to_char(task_last_modified_date_time, 'YYYY-MM-DD hh24:mi:ss') desc) AS LAST_TASK_FINISH_SEQ,
                po_total_amount,
                po_status,
                CASE 
                    WHEN po_status = 101 THEN po_total_amount   
                    ELSE 0
                END as POs_COMPLETED,
                po_type,
                CASE 
                    WHEN po_type = 100 THEN po_total_amount 
                    ELSE 0
                END as "COMMITTED"
        FROM project_complete_data
        order by project_name, custom_lot_no, to_char(task_last_modified_date_time, 'YYYY-MM-DD hh24:mi:ss') desc
    )
    where task_finished = 1
    order by project_name, custom_lot_no, last_modified_date_time desc
)
where last_task_finish_seq = 1;

但是你可以看到有一个嵌套查询,里面还有另一个查询。虽然它得到了结果,但它看起来很奇怪。

我可以将它减少到一个嵌套查询,还是有另一种方法来编写相同的查询而不嵌套。

实际上,当我试图在那里找到总和时,我陷入了最里面的查询。如果我使用

CASE 
    WHEN po_status = 101 THEN SUM(po_total_amount) OVER (PARTITION BY custom_lot_no, task_finished ORDER BY to_char(task_last_modified_date_time, 'YYYY-MM-DD hh24:mi:ss') desc) 
    ELSE 0
END as TOTAL_POS_COMPLETED,

那么对于很多Bldg C1|Parcel 01&*,我在last_task_finish_seq = 5 得到总和。如果我在外部查询中使用where last_task_finish_seq = 1。然后我得到总和 0。因为last_task_finish_seq = 1 总和为 0。

如果我在最内部的嵌套查询或上面提供的数据上计算总和和百分比。然后一个嵌套查询将自动删除。

如何删除一个嵌套查询或编写此查询而不使用任何子查询?

以下是获取我上面显示的所有数据的实际查询。所以基本上这是我内心最嵌套的查询。我把所有的数据都放在了上面的表格里,方便运行。

select 
        poh.project_id,
        cp.proj_company_name,
        cp.project_name,        
        u.custom_lot_no, 
        st.task_name, 
        NVL(to_char(st.original_finish_date), ' ') AS TASK_ACTUAL_END_DATE,                                                 -- Task Actual End date
        st.finish_date AS TASK_FINISH_DATE,
        st.is_finished AS TASK_FINISHED,
        st.last_modified_date AS TASK_LAST_MODIFIED_DATE,
        to_char(st.last_modified_date, 'YYYY-MM-DD hh24:mi:ss') AS TASK_LAST_MODIFIED_DATE_TIME,
        ROW_NUMBER() OVER (PARTITION BY u.custom_lot_no, st.is_finished ORDER BY to_char(st.last_modified_date, 'YYYY-MM-DD hh24:mi:ss') desc) AS LAST_TASK_FINISH_SEQ,
        poh.po_total_amount,
        poh.po_status,
        CASE 
            WHEN (poh.po_status = 101) THEN poh.po_total_amount       -- Approved PO
            ELSE 0
        END as POs_COMPLETED,
        poh.po_type,
        CASE 
            WHEN (poh.po_type = 100) THEN poh.po_total_amount         -- System Generated PO
            ELSE 0
        END as "COMMITTED"
    FROM po_header poh                          
    inner join unit u on poh.unit_id = u.unit_id                    -- POs must be created for a lot to populate on this report 
    inner join schedule s on u.con_schedule_id = s.schedule_id              
    inner join company_project cp on poh.project_id = cp.project_id 
    inner join company_project_setting cps on cp.project_id = cps.project_id
    inner join po_header_status_lk pohslk on poh.po_status = pohslk.code 
    LEFT JOIN schedule_task st on poh.schedule_task_id = st.schedule_task_id 
    LEFT join schedule s on st.schedule_id = s.schedule_id
    WHERE poh.company_id =  653 
    AND poh.po_type = 100                       -- Only System Generated POs
    AND poh.po_status in ('100', '101')         -- PO Must be open (100) and approved (101)
    AND u.status_id in ('102', '103')           -- Only Include Lots that are Construction Status: In Production (102) or Completed(103)
    And s.status = 101                          -- A schedule must be approved
    AND (
        CASE
                WHEN  (cps.construction_type  = 0 and st.is_finished = 1 and (poh.schedule_task_id is not null or poh.schedule_task_id > 0) )THEN -9999
                WHEN  (cps.construction_type in ('1', '2')) THEN -9999
            END
    ) = -9999
    order by cp.project_name, u.custom_lot_no, to_char(st.last_modified_date, 'YYYY-MM-DD hh24:mi:ss') desc

谢谢

【问题讨论】:

  • 多个嵌套级别的子查询并不少见,为什么你觉得这很奇怪?通常所做的是在顶部的WITH 子句中编写连续的子查询,从最里面的子查询开始,一直到最后的SELECT。然后每个子查询都可以引用以前的子查询。单独的问题:当总承诺为零时,为什么需要将完成百分比显示为零?那不应该更好地显示为NULL吗?事实上,您无法区分“未提交”和“0 of 12”,尽管在大多数情况下它们会被视为不同。
  • @mathguy 我要求我的前辈减少这种嵌套,这就是我这样做的原因。我对查询没有任何问题。在我的一份报告中,我必须将列中的所有百分比相加。可能对这份报告也有同样的要求。这就是我使用 0 而不是 null 的原因。所以我可以添加所有的百分比。

标签: oracle oracle-sqldeveloper


【解决方案1】:

减少到一个子查询

Select project_name,
custom_lot_no as "Lot#",
task_name AS "Last Completed Task with a PO",
task_actual_end_date as "Task Actual End Date",
TOTAL_POS_COMPLETED as "Total POs Completed",
TOTAL_COMMITED as "Total Committed",
Round(NVL((TOTAL_POS_COMPLETED / NULLIF(TOTAL_COMMITED, 0)) ,0) * 100) || '%' AS "% Completed"
from(
    select 
        project_id,
        proj_company_name,
        project_name,       
        custom_lot_no, 
        task_name,
        NVL(to_char(task_actual_end_date), ' ') AS TASK_ACTUAL_END_DATE,
        task_finish_date AS TASK_FINISH_DATE,
        task_finished AS TASK_FINISHED,
        to_char(task_last_modified_date_time, 'YYYY-MM-DD hh24:mi:ss') as last_modified_date_time,
        ROW_NUMBER() OVER (PARTITION BY custom_lot_no, task_finished ORDER BY to_char(task_last_modified_date_time, 'YYYY-MM-DD hh24:mi:ss') desc) AS LAST_TASK_FINISH_SEQ,
        po_total_amount,
        po_status,
        CASE 
            WHEN po_status = 101 THEN po_total_amount   
            ELSE 0
        END as POs_COMPLETED,
        SUM(
            CASE 
                WHEN po_status = 101 THEN po_total_amount 
                ELSE 0 
            END
        ) OVER (PARTITION BY custom_lot_no, task_finished) AS TOTAL_POS_COMPLETED,
        po_type,
        CASE 
            WHEN po_type = 100 THEN po_total_amount 
            ELSE 0
        END as "COMMITTED",
        SUM(
            CASE 
                WHEN po_type = 100 THEN po_total_amount 
                ELSE 0 
            END
        ) OVER (PARTITION BY custom_lot_no, task_finished) AS TOTAL_COMMITED
    FROM project_complete_data
    order by project_name, custom_lot_no, to_char(task_last_modified_date_time, 'YYYY-MM-DD hh24:mi:ss') desc
)where last_task_finish_seq = 1 and task_finished = 1;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多