Oracle SQL, getting a value and using it in multiple case statements - sql

I'm trying to figure out how to get a result from a case statement, then use that result in several other case statements throughout the query. It should work the way that I am getting the "TransactionDate", but also for "Period", "BudgetYear", "CalendarMonth", and "CalendarYear". The result of the case statement would be replacing where it has "aila.ACCOUNTING_DATE" in each of those statements. I was considering trying case statements inside of each case statement, but that would be extremely long and I was thinking there had to be a better way.
SELECT
r.TRANSACTION_ID,
CASE
WHEN TRANSACTION_TYPE = 'RECEIVE'
THEN r.PRIMARY_QUANTITY * l.UNIT_PRICE
WHEN TRANSACTION_TYPE = 'RETURN TO VENDOR'
THEN -1 * (r.PRIMARY_QUANTITY * l.UNIT_PRICE)
END AS "Total",
glcc.SEGMENT5 AS BinNumber,
CAST(SUBSTR(d.ATTRIBUTE2, -2) AS INT) AS LineNumber,
CASE
WHEN r.PRIMARY_QUANTITY * l.UNIT_PRICE = aila.AMOUNT
THEN aila.ACCOUNTING_DATE
ELSE (SELECT MAX(ACCOUNTING_DATE) FROM AP_INVOICE_LINES_ALL WHERE d.PO_DISTRIBUTION_ID = PO_DISTRIBUTION_ID)
END AS TransactionDate,
CASE
WHEN EXTRACT(MONTH FROM aila.ACCOUNTING_DATE) >= 9
THEN EXTRACT(MONTH FROM aila.ACCOUNTING_DATE) - 8
ELSE
EXTRACT(MONTH FROM aila.ACCOUNTING_DATE) + 4
END AS Period,
CASE
WHEN EXTRACT(MONTH FROM aila.ACCOUNTING_DATE) >= 9
THEN EXTRACT(YEAR FROM aila.ACCOUNTING_DATE) + 1
ELSE
EXTRACT(YEAR FROM aila.ACCOUNTING_DATE)
END AS BudgetYear,
EXTRACT(MONTH FROM aila.ACCOUNTING_DATE) AS CalendarMonth,
EXTRACT(YEAR FROM aila.ACCOUNTING_DATE) AS CalendarYear,
s.VENDOR_ID AS VendorId,
s.VENDOR_NAME AS VendorName,
h.SEGMENT1 AS PONumber,
l.LINE_NUM AS POLineNumber
FROM
RCV_TRANSACTIONS r
JOIN
PO_DISTRIBUTIONS_ALL d
ON r.PO_LINE_ID = d.PO_LINE_ID
JOIN
GL_CODE_COMBINATIONS glcc
ON d.CODE_COMBINATION_ID = glcc.CODE_COMBINATION_ID
LEFT OUTER JOIN
AP_SUPPLIERS s
ON s.VENDOR_ID = r.VENDOR_ID
LEFT OUTER JOIN
PO_HEADERS_ALL h
ON h.PO_HEADER_ID = d.PO_HEADER_ID
LEFT OUTER JOIN
PO.PO_LINES_ALL l
ON l.PO_LINE_ID = r.PO_LINE_ID
LEFT OUTER JOIN
AP_INVOICE_LINES_ALL aila
ON d.PO_DISTRIBUTION_ID = aila.PO_DISTRIBUTION_ID
AND r.PRIMARY_QUANTITY * l.UNIT_PRICE = aila.AMOUNT
WHERE
(TRANSACTION_TYPE = 'RECEIVE' or TRANSACTION_TYPE = 'RETURN TO VENDOR')
AND
(glcc.SEGMENT2 = '1070'
OR
glcc.SEGMENT2 = '1071');

You can put the joins and initial case expression in an inline view or CTE (common table expression, a.k.a subquery factoring), and then query that - you can then refer to the case expression's column alias:
WITH CTE AS (
SELECT
r.TRANSACTION_ID,
CASE
WHEN TRANSACTION_TYPE = 'RECEIVE'
THEN r.PRIMARY_QUANTITY * l.UNIT_PRICE
WHEN TRANSACTION_TYPE = 'RETURN TO VENDOR'
THEN -1 * (r.PRIMARY_QUANTITY * l.UNIT_PRICE)
END AS "Total",
glcc.SEGMENT5 AS BinNumber,
CAST(SUBSTR(d.ATTRIBUTE2, -2) AS INT) AS LineNumber,
CASE
WHEN r.PRIMARY_QUANTITY * l.UNIT_PRICE = aila.AMOUNT
THEN aila.ACCOUNTING_DATE
ELSE (SELECT MAX(ACCOUNTING_DATE) FROM AP_INVOICE_LINES_ALL WHERE d.PO_DISTRIBUTION_ID = PO_DISTRIBUTION_ID)
END AS TransactionDate,
s.VENDOR_ID AS VendorId,
s.VENDOR_NAME AS VendorName,
h.SEGMENT1 AS PONumber,
l.LINE_NUM AS POLineNumber
FROM
RCV_TRANSACTIONS r
JOIN
PO_DISTRIBUTIONS_ALL d
ON r.PO_LINE_ID = d.PO_LINE_ID
JOIN
GL_CODE_COMBINATIONS glcc
ON d.CODE_COMBINATION_ID = glcc.CODE_COMBINATION_ID
LEFT OUTER JOIN
AP_SUPPLIERS s
ON s.VENDOR_ID = r.VENDOR_ID
LEFT OUTER JOIN
PO_HEADERS_ALL h
ON h.PO_HEADER_ID = d.PO_HEADER_ID
LEFT OUTER JOIN
PO.PO_LINES_ALL l
ON l.PO_LINE_ID = r.PO_LINE_ID
LEFT OUTER JOIN
AP_INVOICE_LINES_ALL aila
ON d.PO_DISTRIBUTION_ID = aila.PO_DISTRIBUTION_ID
AND r.PRIMARY_QUANTITY * l.UNIT_PRICE = aila.AMOUNT
WHERE
(TRANSACTION_TYPE = 'RECEIVE' or TRANSACTION_TYPE = 'RETURN TO VENDOR')
AND
(glcc.SEGMENT2 = '1070'
OR
glcc.SEGMENT2 = '1071')
)
SELECT
TRANSACTION_ID,
"Total",
BinNumber,
LineNumber,
TransactionDate,
CASE
WHEN EXTRACT(MONTH FROM TransactionDate) >= 9
THEN EXTRACT(MONTH FROM TransactionDate) - 8
ELSE
EXTRACT(MONTH FROM TransactionDate) + 4
END AS Period,
CASE
WHEN EXTRACT(MONTH FROM TransactionDate) >= 9
THEN EXTRACT(YEAR FROM TransactionDateE) + 1
ELSE
EXTRACT(YEAR FROM TransactionDate)
END AS BudgetYear,
EXTRACT(MONTH FROM TransactionDate) AS CalendarMonth,
EXTRACT(YEAR FROM TransactionDate) AS CalendarYear,
VendorId,
VendorName,
PONumber,
POLineNumber
FROM
CTE;
So the CTE query is everything from your initial query minus the four expressions that referred to aila.ACCOUNTING_DATE. And the query against CTE gets all the columns from that and adds the expressions for those four, but now referring to TransactionDate instead.

Meaning this as a comment to Alex's answer, but comments don't allow proper formatting of code.
The following use of the CASE expression can be simplified somewhat. Instead of
CASE
WHEN TRANSACTION_TYPE = 'RECEIVE'
THEN r.PRIMARY_QUANTITY * l.UNIT_PRICE
WHEN TRANSACTION_TYPE = 'RETURN TO VENDOR'
THEN -1 * (r.PRIMARY_QUANTITY * l.UNIT_PRICE)
END AS "Total",
you can also write
CASE TRANSACTION_TYPE
WHEN 'RECEIVE' THEN r.PRIMARY_QUANTITY * l.UNIT_PRICE
WHEN 'RETURN TO VENDOR' THEN -1 * (r.PRIMARY_QUANTITY * l.UNIT_PRICE)
END AS "Total",
Alex used a "searched" case expression; what I show above is called a "simple" case expression. Oracle documentation: https://docs.oracle.com/cd/B28359_01/server.111/b28286/expressions004.htm

Related

How to nest multiple case when expressions and add a condition

I am trying to divide customers (contact_key) column who shopped in 2021 (A.TXN_MTH) into new and 'returning' with returning meaning that they had not shopped in the last 12 months (YYYYMM in X.Fiscal_mth_idnt column).
I am using CASE WHEN A.TXN_MTH = MIN(X.FISCAL_MTH_IDNT) THEN 'NEW' which is correct. The next case when should be when the max month before X.TXN_MTH is 12 or more months previous. I have added the 12 months part in the Where statement. Should I be nesting 3 CASE WHEN'S instead of WHERE?
SELECT
T.CONTACT_KEY
, A.TXN_MTH
, CASE WHEN A.TXN_MTH = MIN(X.FISCAL_MTH_IDNT) THEN 'NEW'
WHEN (MAX(CASE WHEN X.FISCAL_MTH_IDNT < A.TXN_MTH THEN X.FISCAL_MTH_IDNT ELSE NULL END)) THEN 'RETURNING'
END AS CUST_TYPE
FROM B_TRANSACTION T
INNER JOIN B_TIME X
ON T.TRANSACTION_DT_KEY = X.DATE_KEY
INNER JOIN A
ON A.CONTACT_KEY = T.CONTACT_KEY AND A.BU_KEY = T.BU_KEY
WHERE (MAX(CASE WHEN X.FISCAL_MTH_IDNT < A.TXN_MTH THEN X.FISCAL_MTH_IDNT ELSE NULL END)) < A.TXN_MTH - (date_format(add_months(concat_ws('-',substr(yearmonth,1,4),substr(yearmonth,5,2),'01'),-12),'yyyyMM')
GROUP BY
T.CONTACT_KEY
, TXN_MTH;
You have not described your tables, so assuming fiscal_mth_idnt is a DATE column then you can use the LAG analytic function to find the previous row's value:
SELECT contact_key,
txn_mth,
CASE
WHEN prev_fiscal_mth_idnt IS NULL
THEN 'NEW'
WHEN ADD_MONTHS(prev_fiscal_mth_idnt, 12) < fiscal_mth_idnt
THEN 'RETURNING'
ELSE 'CURRENT'
END AS cust_type
FROM (
SELECT T.CONTACT_KEY,
A.TXN_MTH,
yearmonth,
X.FISCAL_MTH_IDNT,
LAG(X.FISCAL_MTH_IDNT) OVER (
PARTITION BY T.CONTACT_KEY
ORDER BY X.FISCAL_MTH_IDNT
) AS prev_fiscal_mth_idnt
FROM B_TRANSACTION T
INNER JOIN B_TIME X
ON T.TRANSACTION_DT_KEY = X.DATE_KEY
INNER JOIN A
ON A.CONTACT_KEY = T.CONTACT_KEY AND A.BU_KEY = T.BU_KEY
)
WHERE yearmonth LIKE '2021%';

Why is a value not returned if another value is 0 in SQL query

I have a query that does not return the expense value if the drvalue(Debtor Value) is equal to 0 or NULL,
If i change the drvalue to any value greater than 0, query returns the expenses value.
Drvalue is a sum of all the values for a specific period
Below is the query
SELECT f.vehiclenumber,f.fleettype,f.IsCreditor,
ISNULL(SUM(l.DrValue),0) AS drvalue,
CASE WHEN iscreditor=1 then Sum (DrValue) - Sum(CrValue) else null end AS Profit,
sum(l.CrValue) AS CrValue ,
sum(l.distance) AS LoadDist,
sum(l.DrValue)/DDist AS DRVal ,
d.Liters AS Liters,d.ddist AS DDist, d.DDiesel AS DDiesel, d.DieselCost AS dieslCost,
(MAX(isnull(l.Closingkm,0))-MIN(isnull(l.OpeningKM,0))) AS [CO],ISNULL(SUM(l.DrValue),0) / CASE WHEN (isnull(MAX(l.Closingkm),0)-MIN(isnull(l.OpeningKM,0)))=0 THEN 1 ELSE (isnull(MAX(l.Closingkm),0)-MIN(isnull(l.OpeningKM,0))) END AS TotalCPK,
(d.DieselCost/sum(l.DrValue)) * 100 AS DieselPerc,
SUM(jobdetails.total) AS Expenses,
count(l.vehicleNo) AS LoadCount
FROM tblVehicle AS f
LEFT JOIN (SELECT Vehicleno, loaddate, DrValue, CrValue,Distance, OpeningKM, closingkm FROM tblloads WHERE DrValue IS NOT NULL) AS l ON f.VehicleNumber = l.VehicleNo AND l.loaddate >= '2020-06-01' and l.loaddate <= '2020-06-30'
LEFT JOIN (SELECT fleet , NULLIF(SUM(Liters),0) AS Liters,NULLIF(sum(distance),0) AS DDist, NULLIF(sum(distance)/ CASE WHEN sum(Liters)=0 THEN 1 ELSE sum(Liters) END,0) AS DDiesel, NULLIF(SUM (Manual_Amount),0) AS DieselCost FROM tblinput
WHERE [Date] >= '2020-06-01' And [Date] <= '2020-06-30'
GROUP BY Fleet) AS d ON l.VehicleNo = d.Fleet
LEFT JOIN (SELECT jd.fleet, SUM(Total) AS total From tblJobDetails jd, tbljobcards WHERE tbljobcards.JobID = jd.jobid AND jobdate >= '2020-06-01' AND jobdate <= '2020-06-30' GROUP BY jd.fleet) AS jobdetails ON jobdetails.fleet = l.vehicleno
WHERE VehicleCategory <> 'T'
GROUP BY f.vehiclenumber,f.fleettype,f.IsCreditor,d.Liters,d.ddist, d.DDiesel,d.DieselCost
ORDER BY fleettype
RESULTS

Nested select and joins

I use the code below to calculate the required information from other tables. I used joins to display Names instead of IDs and to get required sums from other tables. I used COALESCE to convert null to Zero.
I had to used it again if I need to sum already COALESCED values, the above code is hard to understand and it's getting harder because I need to add more information, and this is just a small part of the main project so it will be really hard to work with it and will have many error and bugs.
Does it have to be so complicated? Or did I do it wrong? If it has to be complicated like this is there any replacement to get same results with easier way and code? Another RDBMS or anything else?
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
I think it would be good to start with getting down to just one subquery on the Expenses table. Looks like your coalesces in the sub-queries are just to replace nulls with 0 on 1 column - you could just run an UPDATE to fix that, but if not, I've included a way to do that just once in the example below.
You've got (for example):
-- 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
You could do something like this instead:
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
Basically take the conditions out of the where clauses in the sub-query and put them in a case statement within a sum - then you can have all 15 or however many it is items from that EXPENSES table in sub-query item. Only have to coalesce the TOTAL_VALUE once instead of in every sub-query.
You could also make a view that does the summary data.
Are there any proj_id's that don't exist at all in EXPENSES, DURATION, or COSTS? If not, then once you make the above change, you shouldn't have to do any COALESCE's in the main query. If so, then you probably still need to replace a few nulls with 0's - could do that client side if you just want to get the coalesce out of the query.
In general, I find the 'with . . . select' more readable for complex queries, but that may just be a preference thing.
This is the last code faster and cleaner, thanks to aduguid and dandarc
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

issues in Case and when Statement

I have a question about Case and when statements. I have a list of two transtypeid like 10 and 12.
I tried to take sale1 amount like if the transtypeid 11 has a sum amount !=0 means, I need to minus the amount with sum amount of transtypeid 10
I tried a lot but nothing worked.
I have these queries I tried
select
CT.CustomerCode, C.CustomerName,
sale1 = case
when (ct.TransTypeID = 11) and (sum(ct.OVAmount - ct.OVDiscount) != 0)
then sum(ct.OVAmount - ct.OVDiscount) - sum(ct.OVAmount - ct.OVDiscount)
else 0
end,
C.CountryCode, C.CityCode
from
CustomerTransactions CT
inner join
Customers C ON CT.CustomerCode = C.CustomerCode
where
ct.TransDate >= '2015-01-01'
and ct.TransDate <= '2015-12-31'
and ct.TransTypeID in (10, 11)
group by
ct.CustomerCode, c.CustomerName, c.CountryCode, c.CityCode
Try calculate sale1 with this SQL code:
CASE WHEN
SUM(CASE WHEN ct.TransTypeID = 11
THEN ct.OVAmount - ct.OVDiscount
ELSE 0 END) != 0
THEN
SUM(CASE WHEN ct.TransTypeID = 11
THEN ct.OVAmount - ct.OVDiscount
ELSE O END)
- SUM(CASE WHEN ct.TransTypeID = 10
THEN ct.OVAmount - ct.OVDiscount
ELSE 0 END)
ELSE 0 END
I'm not sure that I understand what you need. But I give it a try since you are in hurry.
Something like this, maybe?
select
CT1.CustomerCode, C.CustomerName,
sale1 =
case
when ( sum(ct1.OVAmount - ct1.OVDiscount) != 0 )
then sum( ct1.OVAmount - ct1.OVDiscount ) - sum( ct2.OVAmount - ct2.OVDiscount )
else
0
end,
C.CountryCode, C.CityCode
from
Customers c
Inner join CustomerTransactions CT1 ON ( CT1.CustomerCode = C.CustomerCode ) And ( ct1.TransTypeID = 11 )
Inner join CustomerTransactions CT2 ON ( CT2.CustomerCode = C.CustomerCode ) And ( ct2.TransTypeID = 10 )
where
( ct1.TransDate >= '2015-01-01' )
and ( ct1.TransDate < '2016-01-01' )
and ( ct2.TransDate >= '2015-01-01' )
and ( ct2.TransDate < '2016-01-01' )
group by
ct1.CustomerCode,c.CustomerName,c.CountryCode,c.CityCode
Using CTEs:
with
cte10 ( CustomerId, amount ) as (
select
customerId, sum( amount ) as amount
from
CustomerTransaction
where
( Type = 1 )
group by CustomerId
),
cte11 ( CustomerId, amount ) as (
select
customerId, sum( amount ) as amount
from
CustomerTransaction
where
( Type = 2 )
group by CustomerId
)
select
c.Id, c.Description,
sale1 =
case
when ( cte10.amount <> 0 )
then cte10.amount - cte11.amount
else
0
end
from
Customer c
Inner join cte10 on ( cte10.CustomerId = C.id )
inner join cte11 on ( cte11.Customerid = C.id )

Select with subquery select not working

I keep getting that error on this code. I am not using EXISTS.Please Help.
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
SQL:
If ISDATE(#grpsearch) = 1
SELECT grp.GroupID,
vlanlist.InternetType,
grp.GroupName, cast(grp.StartDateTime as date) as StartDate,
convert(varchar,cast(grp.StartDateTime as time),100) as starttime,
(select case when datepart(hh,convert(datetime,grp.StartDateTime)) > 12 then datepart(hh,convert(datetime,grp.StartDateTime))-12
else case when datepart(hh,convert(datetime,grp.StartDateTime)) = 0 then '12' else datepart(hh,convert(datetime,grp.StartDateTime)) end end as starthour,
datepart(mi,convert(datetime,grp.StartDateTime)) as startmin, case when datepart(hh,convert(datetime,grp.StartDateTime)) >= 12 then 'PM' else 'AM' end as startperiod),
cast(grp.enddatetime as date) as EndDate,
convert(varchar,cast(grp.EndDateTime as time),100) as EndTime,
grp.UserInitials,
grp.UserComments,
roomlist.RoomName,
jacklist.JackNumber
FROM a_Cisco.dbo.grp_internet as grp left outer join
dbo.jacklist as jacklist ON grp.intJack = jacklist.intJack left outer join
dbo.roomlist as roomlist ON grp.intRoom = roomlist.intROom left outer join
dbo.vlanlist as vlanlist ON grp.VlanID = vlanlist.VlanID
WHERE (convert(varchar,cast(grp.StartDateTime as date),100) = #grpsearch)
The problem is this part of the query:
(select case when datepart(hh,convert(datetime,grp.StartDateTime)) > 12
then datepart(hh,convert(datetime,grp.StartDateTime))-12
else case when datepart(hh,convert(datetime,grp.StartDateTime)) = 0
then '12' else datepart(hh,convert(datetime,grp.StartDateTime))
end
end as starthour,
First, you don't need the select at all. Second, you are missing the closing parentheses ()). I would suggest:
(case when datepart(hh,convert(datetime,grp.StartDateTime)) > 12
then datepart(hh,convert(datetime,grp.StartDateTime))-12
else (case when datepart(hh,convert(datetime,grp.StartDateTime)) = 0
then '12'
else datepart(hh,convert(datetime,grp.StartDateTime))
end)
end) as starthour,