嵌套选择和联接

时间:2018-08-21 17:50:03

标签: sql firebird

我使用下面的代码从其他表中计算所需的信息。我使用联接来显示名称而不是ID,并从其他表中获取所需的总和。我使用COALESCE将null转换为零。

如果我需要加总COALESCED值,就不得不再次使用它,上面的代码很难理解,而且由于需要添加更多信息而变得越来越困难,这只是主项目的一小部分,因此真的很难使用它,并且会有很多错误和错误。

它必须是如此复杂吗?还是我做错了?如果必须这样复杂,是否有任何替代方法可以通过更简单的方法和代码来获得相同的结果?另一个RDBMS还是其他?

SELECT P.PROJ_ID, P.PROJ_STATUS, P.TYPE_ID, PT.TYPE_NAME, P.CLASS_ID, CLA.CLASS_NAME, P.PROJ_NO, P.PROJ_YEAR, P.PROJ_NAME, P.OLD_PROJ_NAME, 
P.AGENCY_ID, A.AGENCY_NAME, P.CONTRACT_NO, P.CONTRACT_DATE, P.MINISTRY_ID, M.MINISTRY_NAME, 
P.DIRECTORATE_ID, DIR.DIRECTORATE_NAME, 
P.COST, P.ESTIMATED_COST, COALESCE(CO.ADDED_COSTS, 0) AS ADDED_COSTS, (COALESCE(P.COST, 0) + COALESCE(CO.ADDED_COSTS, 0)) AS TOTAL_COST, 
P.ALLOCATION, 
COALESCE(EPY.PAST_YEARS, 0) AS PAST_YEARS, 
COALESCE(EF.PAST_MONTHS, 0) AS PAST_MONTHS, 
COALESCE(ECM.CURRENT_MONTH, 0) AS CURRENT_MONTH,
COALESCE(ECY.CURRENT_YEAR, 0) AS CURRENT_YEAR,
COALESCE(E.TOTAL_EXPENSES, 0) AS TOTAL_EXPENSES,

COALESCE(CASH_EPY.CASH_PAST_YEARS, 0) AS CASH_PAST_YEARS, 
COALESCE(CASH_EF.CASH_PAST_MONTHS, 0) AS CASH_PAST_MONTHS, 
COALESCE(CASH_ECM.CASH_CURRENT_MONTH, 0) AS CASH_CURRENT_MONTH,
COALESCE(CASH_ECY.CASH_CURRENT_YEAR, 0) AS CASH_CURRENT_YEAR,
COALESCE(CASH_E.CASH_TOTAL_EXPENSES, 0) AS CASH_TOTAL_EXPENSES,

COALESCE(TOTAL_E.TOTAL_EXPENSES_CASH, 0) AS TOTAL_EXPENSES_CASH,

((COALESCE(P.COST, 0) + COALESCE(CO.ADDED_COSTS, 0)) - COALESCE(E.TOTAL_EXPENSES, 0)) AS REMAINING,
P.DURATION, COALESCE(DU.ADDED_DURATIONS, 0) AS ADDED_DURATIONS,
(COALESCE(P.DURATION, 0) + COALESCE(DU.ADDED_DURATIONS, 0)) AS TOTAL_DURATION, P.START_DATE, P.FINISH_DATE, 
P.GOVERNORATE_ID, G.GOVERNORATE_NAME, P.PROVINCE_ID, PR.PROVINCE_NAME, P.DISTRICT_ID, D.DISTRICT_NAME, 
P.TOWN_ID, T.TOWN_NAME, 

COALESCE( (E.TOTAL_EXPENSES / (COALESCE(P.COST, 0) + COALESCE(CO.ADDED_COSTS, 0)))/100, 0) AS FINANCIAL_ACHIEVEMENT,

P.MATERIAL_ACHIEVEMENT, P.NOTES
FROM PROJECTS P

INNER JOIN PROJECTS_TYPES PT
ON P.TYPE_ID = PT.TYPE_ID

INNER JOIN CLASSES CLA
ON P.CLASS_ID = CLA.CLASS_ID

INNER JOIN AGENCIES A
ON P.AGENCY_ID = A.AGENCY_ID

LEFT JOIN MINISTRIES M
ON P.MINISTRY_ID = M.MINISTRY_ID

LEFT JOIN DIRECTORATES DIR
ON P.DIRECTORATE_ID = DIR.DIRECTORATE_ID

INNER JOIN GOVERNORATES G
ON P.GOVERNORATE_ID = G.GOVERNORATE_ID

LEFT JOIN PROVINCES PR
ON P.PROVINCE_ID = PR.PROVINCE_ID

LEFT JOIN DISTRICTS D
ON P.DISTRICT_ID = D.DISTRICT_ID

LEFT JOIN TOWNS T
ON P.TOWN_ID = T.TOWN_ID

-- ADDED COSTS
LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(ADDED_VALUE, 0) - COALESCE(REMOVED_VALUE, 0)) as ADDED_COSTS
FROM COSTS
GROUP BY PROJ_ID ) AS CO
ON P.PROJ_ID = CO.PROJ_ID

-- EXPENSES FROM PAST YEARS
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as PAST_YEARS
  FROM EXPENSES WHERE EXTRACT(YEAR FROM DOC_DATE) < EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = FALSE
GROUP BY PROJ_ID ) AS EPY
ON P.PROJ_ID= EPY.PROJ_ID

-- EXPENSES FROM PAST MONTHS IN CUREENT YEAR
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as PAST_MONTHS
FROM EXPENSES WHERE EXTRACT(MONTH FROM DOC_DATE) < EXTRACT(MONTH FROM CURRENT_DATE) 
AND EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE)  AND CASH_DEDUCTIONS = FALSE
GROUP BY PROJ_ID ) AS EF
ON P.PROJ_ID= EF.PROJ_ID

-- EXPENSES FROM CURRENT MONTH AND YEAR
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as CURRENT_MONTH
  FROM EXPENSES WHERE EXTRACT(MONTH FROM DOC_DATE) = EXTRACT(MONTH FROM CURRENT_DATE) AND EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = FALSE
GROUP BY PROJ_ID ) AS ECM
ON P.PROJ_ID= ECM.PROJ_ID

-- SUM OF EXPENSES IN CURRENT YEAR
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as CURRENT_YEAR
  FROM EXPENSES WHERE EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = FALSE
GROUP BY PROJ_ID ) AS ECY
ON P.PROJ_ID= ECY.PROJ_ID

-- TOTAL EXPENSES FROM ALL TIME
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as TOTAL_EXPENSES
FROM EXPENSES WHERE CASH_DEDUCTIONS = FALSE
GROUP BY PROJ_ID ) AS E
ON P.PROJ_ID= E.PROJ_ID

-- CASH DEDUCTIONS SUMS
-- CASH DEDUCTIONS FROM PAST YEARS
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as CASH_PAST_YEARS
  FROM EXPENSES WHERE EXTRACT(YEAR FROM DOC_DATE) < EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = TRUE
GROUP BY PROJ_ID ) AS CASH_EPY
ON P.PROJ_ID= CASH_EPY.PROJ_ID

-- CASH DEDUCTIONS FROM PAST MONTHS IN CUREENT YEAR
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as CASH_PAST_MONTHS
FROM EXPENSES WHERE EXTRACT(MONTH FROM DOC_DATE) < EXTRACT(MONTH FROM CURRENT_DATE) 
AND EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE)  AND CASH_DEDUCTIONS = TRUE
GROUP BY PROJ_ID ) AS CASH_EF
ON P.PROJ_ID= CASH_EF.PROJ_ID

-- CASH DEDUCTIONS FROM CURRENT MONTH AND YEAR
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as CASH_CURRENT_MONTH
  FROM EXPENSES WHERE EXTRACT(MONTH FROM DOC_DATE) = EXTRACT(MONTH FROM CURRENT_DATE) AND EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = TRUE
GROUP BY PROJ_ID ) AS CASH_ECM
ON P.PROJ_ID= CASH_ECM.PROJ_ID

-- SUM OF CASH DEDUCTIONS IN CURRENT YEAR
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as CASH_CURRENT_YEAR
  FROM EXPENSES WHERE EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = TRUE
GROUP BY PROJ_ID ) AS CASH_ECY
ON P.PROJ_ID= CASH_ECY.PROJ_ID

-- TOTAL CASH DEDUCTIONS FROM ALL TIME
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as CASH_TOTAL_EXPENSES
FROM EXPENSES WHERE CASH_DEDUCTIONS = TRUE
GROUP BY PROJ_ID ) AS CASH_E
ON P.PROJ_ID= CASH_E.PROJ_ID

-- TOTAL EXPENSES AND CASH DEDUCTIONS FROM ALL TIME
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as TOTAL_EXPENSES_CASH
FROM EXPENSES
GROUP BY PROJ_ID ) AS TOTAL_E
ON P.PROJ_ID= TOTAL_E.PROJ_ID

-- ADDED DURATIONS
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(ADDED_VALUE, 0) - COALESCE(REMOVED_VALUE, 0)) as ADDED_DURATIONS
FROM DURATIONS
GROUP BY PROJ_ID ) AS DU
ON P.PROJ_ID= DU.PROJ_ID
ORDER BY P.PROJ_YEAR, P.TYPE_ID, P.PROJ_NO 

2 个答案:

答案 0 :(得分:0)

我认为从Expenses表上的仅一个子查询开始会是一个很好的选择。看起来您在子查询中的合并只是将0替换为1列上的空值-您可以运行UPDATE来解决此问题,但是如果没有,我在下面的示例中提供了一种仅执行一次的方法。

您有(例如):

-- TOTAL CASH DEDUCTIONS FROM ALL TIME
LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as CASH_TOTAL_EXPENSES
FROM EXPENSES WHERE CASH_DEDUCTIONS = TRUE
GROUP BY PROJ_ID ) AS CASH_E
ON P.PROJ_ID= CASH_E.PROJ_ID

-- TOTAL EXPENSES AND CASH DEDUCTIONS FROM ALL TIME
  LEFT JOIN (SELECT PROJ_ID, SUM(COALESCE(TOTAL_VALUE, 0)) as TOTAL_EXPENSES_CASH
FROM EXPENSES
GROUP BY PROJ_ID ) AS TOTAL_E
ON P.PROJ_ID= TOTAL_E.PROJ_ID

您可以改为执行以下操作:

with MY_EXPENSES AS 
   (
   select COALESCE(TOTAL_VALUE, 0) as MY_TOTAL_VALUE, exp.*
   from EXPENSES),

   EXPENSES_SUMMARY AS
   (
   SELECT PROJ_ID,
       sum(case when CASH_DEDUCTIONS = TRUE 
           then MY_TOTAL_VALUE else 0 
           end) as CASH_TOTAL_EXPENSES,
       sum(MY_TOTAL_VALUE) as TOTAL_EXPENSES_CASH
    FROM MY_EXPENSES
    GROUP BY PROJ_ID )

<Big Query>
LEFT OUTER JOIN EXPENSES_SUMMARY es P.PROJ_ID= TOTAL_E.PROJ_ID

基本上从子查询的where子句中取出条件,并将它们放在总和内的case语句中-然后,子查询项中可以包含该EXPENSES表中的所有15个项,或者其中有很多项。只需合并一次TOTAL_VALUE,而不是在每个子查询中合并一次。

您还可以创建一个包含摘要数据的视图。

在费用,持续时间或费用中是否根本不存在任何proj_id?如果没有,那么一旦进行了上述更改,就不必在主查询中进行任何COALESCE操作。如果是这样,那么您可能仍需要用0代替一些空值-如果您只是想从查询中合并,可以在客户端执行此操作。

通常,我会找到'with'。 。 。选择>对于复杂查询更具可读性,但这可能只是一个优先选择。

答案 1 :(得分:0)

这是最后一个更快,更干净的代码,这要归功于aduguiddandarc

WITH
EXPENSES_SUMS
AS
(
    SELECT 
          PROJ_ID
        , SUM(CASE 
                WHEN EXTRACT(YEAR FROM DOC_DATE) < EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = FALSE 
                THEN TOTAL_VALUE
          END) AS PAST_YEARS
        , SUM(CASE  
                WHEN EXTRACT(MONTH FROM DOC_DATE) < EXTRACT(MONTH FROM CURRENT_DATE) AND EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = FALSE
                THEN TOTAL_VALUE
          END) AS PAST_MONTHS
        , SUM(CASE  
                WHEN EXTRACT(MONTH FROM DOC_DATE) = EXTRACT(MONTH FROM CURRENT_DATE) AND EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = FALSE
                THEN TOTAL_VALUE 
          END) AS CURRENT_MONTH
        , SUM(CASE  
                WHEN EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = FALSE
                THEN TOTAL_VALUE
          END) AS CURRENT_YEAR
        , SUM(CASE  
                WHEN CASH_DEDUCTIONS = FALSE
                THEN TOTAL_VALUE
          END) AS TOTAL_EXPENSES
        , SUM(CASE  
                WHEN EXTRACT(YEAR FROM DOC_DATE) < EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = TRUE
                THEN TOTAL_VALUE
          END) AS CASH_PAST_YEARS
        , SUM(CASE  
                WHEN EXTRACT(MONTH FROM DOC_DATE) < EXTRACT(MONTH FROM CURRENT_DATE) AND EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE)  AND CASH_DEDUCTIONS = TRUE
                THEN TOTAL_VALUE 
          END) AS CASH_PAST_MONTHS
        , SUM(CASE  
                WHEN EXTRACT(MONTH FROM DOC_DATE) = EXTRACT(MONTH FROM CURRENT_DATE) AND EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = TRUE
                THEN TOTAL_VALUE
          END) AS CASH_CURRENT_MONTH
        , SUM(CASE  
                WHEN EXTRACT(YEAR FROM DOC_DATE) = EXTRACT(YEAR FROM CURRENT_DATE) AND CASH_DEDUCTIONS = TRUE
                THEN TOTAL_VALUE
          END) AS CASH_CURRENT_YEAR
        , SUM(CASE  
                WHEN CASH_DEDUCTIONS = TRUE
                THEN TOTAL_VALUE
          END) AS CASH_TOTAL_EXPENSES
        , SUM(TOTAL_VALUE) AS TOTAL_EXPENSES_CASH
        --you can add more columns with your conditions here in case expressions

    FROM 
        EXPENSES
    GROUP BY 
        PROJ_ID
)
, 
COSTS_SUMS
AS
(
    SELECT 
          PROJ_ID
        , SUM(COALESCE(ADDED_VALUE, 0) - COALESCE(REMOVED_VALUE, 0)) AS ADDED_COSTS
        --you can add more columns with your conditions here in case expressions

    FROM 
        COSTS
    GROUP BY 
        PROJ_ID
)
, 
DURATIONS_SUMS
AS
(
    SELECT 
          PROJ_ID
        , SUM(COALESCE(ADDED_VALUE, 0) - COALESCE(REMOVED_VALUE, 0)) AS ADDED_DURATIONS
        --you can add more columns with your conditions here in case expressions

    FROM 
        DURATIONS
    GROUP BY 
        PROJ_ID
)
SELECT 
      P.PROJ_ID
    , P.PROJ_STATUS
    , P.TYPE_ID
    , PT.TYPE_NAME
    , P.CLASS_ID
    , CLA.CLASS_NAME
    , P.PROJ_NO
    , P.PROJ_YEAR
    , P.PROJ_NAME
    , P.OLD_PROJ_NAME
    , P.AGENCY_ID
    , A.AGENCY_NAME
    , P.CONTRACT_NO
    , P.CONTRACT_DATE
    , P.MINISTRY_ID
    , M.MINISTRY_NAME
    , P.DIRECTORATE_ID
    , DIR.DIRECTORATE_NAME
    , P.COST
    , P.ESTIMATED_COST
    , COALESCE(CO.ADDED_COSTS, 0) AS ADDED_COSTS
    , (COALESCE(P.COST, 0) + COALESCE(CO.ADDED_COSTS, 0)) AS TOTAL_COST
    , P.ALLOCATION
    , COALESCE(ED.PAST_YEARS, 0) AS PAST_YEARS
    , COALESCE(ED.PAST_MONTHS, 0) AS PAST_MONTHS
    , COALESCE(ED.CURRENT_MONTH, 0) AS CURRENT_MONTH
    , COALESCE(ED.CURRENT_YEAR, 0) AS CURRENT_YEAR
    , COALESCE(ED.TOTAL_EXPENSES, 0) AS TOTAL_EXPENSES
    , COALESCE(ED.CASH_PAST_YEARS, 0) AS CASH_PAST_YEARS
    , COALESCE(ED.CASH_PAST_MONTHS, 0) AS CASH_PAST_MONTHS
    , COALESCE(ED.CASH_CURRENT_MONTH, 0) AS CASH_CURRENT_MONTH
    , COALESCE(ED.CASH_CURRENT_YEAR, 0) AS CASH_CURRENT_YEAR
    , COALESCE(ED.CASH_TOTAL_EXPENSES, 0) AS CASH_TOTAL_EXPENSES
    , COALESCE(ED.TOTAL_EXPENSES_CASH, 0) AS TOTAL_EXPENSES_CASH
    , ((COALESCE(P.COST, 0) + COALESCE(CO.ADDED_COSTS, 0)) - COALESCE(ED.TOTAL_EXPENSES, 0)) AS REMAINING
    , P.DURATION
    , COALESCE(DU.ADDED_DURATIONS, 0) AS ADDED_DURATIONS
    , (COALESCE(P.DURATION, 0) + COALESCE(DU.ADDED_DURATIONS, 0)) AS TOTAL_DURATION
    , P.START_DATE
    , P.FINISH_DATE
    , P.GOVERNORATE_ID
    , G.GOVERNORATE_NAME
    , P.PROVINCE_ID
    , PR.PROVINCE_NAME
    , P.DISTRICT_ID
    , D.DISTRICT_NAME
    , P.TOWN_ID
    , T.TOWN_NAME
    , COALESCE( (ED.TOTAL_EXPENSES / (COALESCE(P.COST, 0) + COALESCE(CO.ADDED_COSTS, 0)))/100, 0) AS FINANCIAL_ACHIEVEMENT
    , P.MATERIAL_ACHIEVEMENT
    , P.NOTES
FROM 
    PROJECTS P
    INNER JOIN PROJECTS_TYPES PT ON P.TYPE_ID = PT.TYPE_ID
    INNER JOIN CLASSES CLA ON P.CLASS_ID = CLA.CLASS_ID
    INNER JOIN AGENCIES A ON P.AGENCY_ID = A.AGENCY_ID
    LEFT JOIN MINISTRIES M ON P.MINISTRY_ID = M.MINISTRY_ID
    LEFT JOIN DIRECTORATES DIR ON P.DIRECTORATE_ID = DIR.DIRECTORATE_ID
    INNER JOIN GOVERNORATES G ON P.GOVERNORATE_ID = G.GOVERNORATE_ID
    LEFT JOIN PROVINCES PR ON P.PROVINCE_ID = PR.PROVINCE_ID
    LEFT JOIN DISTRICTS D ON P.DISTRICT_ID = D.DISTRICT_ID
    LEFT JOIN TOWNS T ON P.TOWN_ID = T.TOWN_ID
    LEFT JOIN EXPENSES_SUMS ED ON P.PROJ_ID = ED.PROJ_ID
    LEFT JOIN COSTS_SUMS CO ON P.PROJ_ID = CO.PROJ_ID
    LEFT JOIN DURATIONS_SUMS DU ON P.PROJ_ID = CO.PROJ_ID
ORDER BY 
      P.PROJ_YEAR
    , P.TYPE_ID
    , P.PROJ_NO