Unable to sum DEMAND in SQL for each Item across Transaction Date - sql

I am trying to create an inventory report from an Oracle database that requires a join on two tables, and to create a calculated column for DEMAND using a CASE statement, since the value for DEMAND depends on the value of the SOURCE column.
Below is the SQL I have written, which executes without error. However, I need a sum of DEMAND across transaction dates (TRAN_DATE), and I am unsure how to do this. Can someone please help with this?
I have also included sample output. For the 090CAP ITEMNO, the demand is OUT_QTY since the value of SOURCE is REQUIRED. However, I want the demand to be the sum of the two demands per TRAN_DATE (i.e. 29,787.1410 + 11,012.8590 = 40,800), and ultimately I do not want to display TRAN_DATE in my results.
Your help is greatly appreciated.
SELECT
ARINVT.ITEMNO,
ARINVT.REV,
ARINVT.DESCRIP,
ARINVT.ONHAND,
V_ARINVT_AVAIL_PROJECT_DTL_EX.OUT_QTY,
V_ARINVT_AVAIL_PROJECT_DTL_EX.SHIP_QUAN,
V_ARINVT_AVAIL_PROJECT_DTL_EX.SHIP_QUAN_NATIVE,
V_ARINVT_AVAIL_PROJECT_DTL_EX.SOURCE,
(CASE
WHEN V_ARINVT_AVAIL_PROJECT_DTL_EX.SOURCE = 'BACKLOG'
THEN V_ARINVT_AVAIL_PROJECT_DTL_EX.SHIP_QUAN_NATIVE
WHEN V_ARINVT_AVAIL_PROJECT_DTL_EX.SOURCE = 'REQUIRED'
THEN V_ARINVT_AVAIL_PROJECT_DTL_EX.OUT_QTY
ELSE 0
END) AS "DEMAND",
ARINVT.PK_HIDE AS "PK_HIDE",
V_ARINVT_AVAIL_PROJECT_DTL_EX.TRAN_DATE
FROM
(((ARINVT LEFT JOIN IQMS.V_ARINVT_AVAIL_PROJECT_DTL_EX ON (ARINVT."ID" = V_ARINVT_AVAIL_PROJECT_DTL_EX."ARINVT_ID"))
LEFT JOIN IQMS.EPLANT ON (ARINVT."EPLANT_ID" = EPLANT."ID")) )
WHERE
( ((ARINVT.PK_HIDE IS NULL) )
OR ((ARINVT.PK_HIDE =' ') )
OR ((ARINVT.PK_HIDE ='N') ) )
ORDER BY
ARINVT.CLASS,
ARINVT.ITEMNO
sample output

A CASE statement can go inside a SUM aggregate function.
SELECT
ARINVT.ITEMNO,
ARINVT.REV,
ARINVT.DESCRIP,
ARINVT.ONHAND,
V_ARINVT_AVAIL_PROJECT_DTL_EX.OUT_QTY,
V_ARINVT_AVAIL_PROJECT_DTL_EX.SHIP_QUAN,
V_ARINVT_AVAIL_PROJECT_DTL_EX.SHIP_QUAN_NATIVE,
V_ARINVT_AVAIL_PROJECT_DTL_EX.SOURCE,
sum(
CASE
WHEN V_ARINVT_AVAIL_PROJECT_DTL_EX.SOURCE = 'BACKLOG'
THEN V_ARINVT_AVAIL_PROJECT_DTL_EX.SHIP_QUAN_NATIVE
WHEN V_ARINVT_AVAIL_PROJECT_DTL_EX.SOURCE = 'REQUIRED'
THEN V_ARINVT_AVAIL_PROJECT_DTL_EX.OUT_QTY
ELSE 0
END
) AS "DEMAND",
ARINVT.PK_HIDE AS "PK_HIDE"
FROM
ARINVT
LEFT JOIN IQMS.V_ARINVT_AVAIL_PROJECT_DTL_EX
ON ARINVT."ID" = V_ARINVT_AVAIL_PROJECT_DTL_EX."ARINVT_ID"
LEFT JOIN IQMS.EPLANT
ON ARINVT."EPLANT_ID" = EPLANT."ID"
WHERE
ARINVT.PK_HIDE IS NULL
OR ARINVT.PK_HIDE IN (' ', 'N')
GROUP BY
ARINVT.ITEMNO,
ARINVT.REV,
ARINVT.DESCRIP,
ARINVT.ONHAND,
V_ARINVT_AVAIL_PROJECT_DTL_EX.OUT_QTY,
V_ARINVT_AVAIL_PROJECT_DTL_EX.SHIP_QUAN,
V_ARINVT_AVAIL_PROJECT_DTL_EX.SHIP_QUAN_NATIVE,
V_ARINVT_AVAIL_PROJECT_DTL_EX.SOURCE,
ARINVT.PK_HIDE
ORDER BY
ARINVT.CLASS,
ARINVT.ITEMNO

Related

SQL CASE WHEN ELSE not working in AWS Athena

I have the script below setup in AWS Athena, the goal is to replace some budget numbers (total) with 0 if they are within a certain category (costitemid). I'm getting the following error in AWS Athena and could use some advice as to why it isn't working. Is the problem that I need to repeat everything in the FROM and GROUP BY in the WHEN and ELSE? Code below the error. Thank you!
SYNTAX_ERROR: line 6:9: 'projectbudgets.projectid' must be an aggregate expression or appear in GROUP BY clause
This query ran against the "acorn-prod-reports" database, unless qualified by the query. Please post the error message on our forum or contact customer support with Query Id: 077f007b-61a0-4f6b-aa1f-dd38bb401218
SELECT
CASE
WHEN projectbudgetlineitems.costitemid IN (462561,462562,462563,462564,462565,462566,478030) THEN (
SELECT
projectbudgets.projectid
, projectbudgetyears.year fiscalYear
, projectbudgetyears.status
, "sum"(((0 * projectbudgetlineitems.unitcost) * (projectbudgetlineitems.costshare * 1E-2))) total
)
ELSE (
SELECT
projectbudgets.projectid
, projectbudgetyears.year fiscalYear
, projectbudgetyears.status
, "sum"(((projectbudgetlineitems.quantity * projectbudgetlineitems.unitcost) * (projectbudgetlineitems.costshare * 1E-2))) total
)
END
FROM
(("acorn-prod-etl".target_acorn_prod_acorn_projectbudgets projectbudgets
INNER JOIN "acorn-prod-etl".target_acorn_prod_acorn_projectbudgetyears projectbudgetyears ON (projectbudgets.id = projectbudgetyears.projectbudgetid))
INNER JOIN "acorn-prod-etl".target_acorn_prod_acorn_projectbudgetlineitems projectbudgetlineitems ON (projectbudgetyears.id = projectbudgetlineitems.projectbudgetyearid))
--WHERE (((projectbudgetlineitems.costitemid <> 478030) AND (projectbudgetlineitems.costitemid < 462561)) OR (projectbudgetlineitems.costitemid > 462566))
GROUP BY projectbudgets.projectid, projectbudgetyears.year, projectbudgetyears.status
Your syntax is wrong (at least according to most SQL dialects.) You can't generally say "SELECT CASE WHEN (condition) THEN (this select clause) ELSE (that select clause) END FROM (tables)"
You can only use CASE to calculate a single value.
But it looks as if the only change between your two inner SELECT clauses is whether you use 0 or the quantity in the final multiplication. And that is perfect for a CASE!
I do not guarantee this will work right off the bat, because I don't have your setup or an idea of your table layout. However, it's a step in the right direction:
SELECT
projectbudgets.projectid
, projectbudgetyears.year fiscalYear
, projectbudgetyears.status
, "sum"(
((
CASE
WHEN projectbudgetlineitems.costitemid IN (462561,462562,462563,462564,462565,462566,478030)
THEN 0
ELSE projectbudgetlineitems.quantity
END * projectbudgetlineitems.unitcost
) * (
projectbudgetlineitems.costshare * 1E-2
))) total
FROM
(("acorn-prod-etl".target_acorn_prod_acorn_projectbudgets projectbudgets
INNER JOIN
"acorn-prod-etl".target_acorn_prod_acorn_projectbudgetyears projectbudgetyears
ON (projectbudgets.id = projectbudgetyears.projectbudgetid))
INNER JOIN "acorn-prod-etl".target_acorn_prod_acorn_projectbudgetlineitems projectbudgetlineitems
ON (projectbudgetyears.id = projectbudgetlineitems.projectbudgetyearid))
GROUP BY
projectbudgets.projectid, projectbudgetyears.year, projectbudgetyears.status
This could solve your problem if you want to sum the items for each project and year and status except for certain line items. Here, it is correct to use a "where" condition and not "case when" :
SELECT
projectbudgets.projectid,
projectbudgetyears.year,
projectbudgetyears.status,
"sum"(((projectbudgetlineitems.quantity * projectbudgetlineitems.unitcost) *
(projectbudgetlineitems.costshare * 1E-2))) total
FROM
(("acorn-prod-etl".target_acorn_prod_acorn_projectbudgets projectbudgets
INNER JOIN "acorn-prod-etl".target_acorn_prod_acorn_projectbudgetyears
projectbudgetyears ON (projectbudgets.id = projectbudgetyears.projectbudgetid))
INNER JOIN "acorn-prod-etl".target_acorn_prod_acorn_projectbudgetlineitems
projectbudgetlineitems ON (projectbudgetyears.id =
projectbudgetlineitems.projectbudgetyearid))
WHERE projectbudgetlineitems.costitemid NOT IN
(462561,462562,462563,462564,462565,462566,478030)
GROUP BY projectbudgets.projectid, projectbudgetyears.year,
projectbudgetyears.status
;

SQL code is removing duplicate values in error

My SQL code is removing duplicate values of "Time" specific to Project Description. For example, if a time value for a specific project is included two or more times, the data is only pulling the value once skewing the results.
I've tried adding SUM(PMTT_DailyTime.Time) as 'Sum of Time" and this creates a different problem and inaccurate results. It multiplies the sum values by the number of an irrelevant field.
SELECT View_ProjectsInfoDecoded.ProjectNbr
, View_ProjectsInfoDecoded.Department
, View_ProjectsInfoDecoded.ProjectDesc
, View_ProjectsInfoDecoded.ProjectStartDate
, View_ProjectsInfoDecoded.ProjectCompletionDate
, View_ProjectsInfoDecoded.VoidInd
, View_ProjectsInfoDecoded.ProjectStatus
, View_ProjectsInfoDecoded.ProjectType
, DatePart("yyyy", PMTT_DailyTime.ReportDate) AS [ReportYear]
, PMTT_DailyTime.Time
, PMTT_DailyTime.VoidInd
, View_ProjectsBuilderInfoDecoded.ProjectHealth
, View_ProjectsBuilderInfoDecoded.PrimaryBuilder
, View_ProjectsBuilderInfoDecoded.CurrentProjectStatus
FROM View_ProjectsInfoDecoded
LEFT JOIN View_ProjectsBuilderInfoDecoded ON View_ProjectsInfoDecoded.Department = View_ProjectsBuilderInfoDecoded.Department AND View_ProjectsInfoDecoded.ProjectNbr = View_ProjectsBuilderInfoDecoded.ProjectNbr
LEFT JOIN PMTT_DailyTime ON (View_ProjectsBuilderInfoDecoded.Department = PMTT_DailyTime.Department) AND (View_ProjectsBuilderInfoDecoded.ProjectNbr= PMTT_DailyTime.ProjectNbr)
WHERE (View_ProjectsInfoDecoded.Department IN ('107'))
And (View_ProjectsInfoDecoded.ProjectStatus <>'Cancel')
And (dbo.View_ProjectsInfoDecoded.VoidInd = 'N' OR dbo.View_ProjectsInfoDecoded.VoidInd IS NULL)
AND (PMTT_DailyTime.VoidInd = 'N' OR PMTT_DailyTime.VoidInd IS NULL)
AND ((DATEDIFF(MONTH, View_ProjectsInfoDecoded.ProjectCompletionDate,GETDATE()) <= 12) OR (View_ProjectsInfoDecoded.ProjectCompletionDate IS NULL) OR (View_ProjectsInfoDecoded.ProjectCompletionDate='' ))
GROUP BY View_ProjectsInfoDecoded.Department, View_ProjectsInfoDecoded.ProjectNbr
, View_ProjectsInfoDecoded.ProjectDesc, View_ProjectsInfoDecoded.ProjectStatus
, View_ProjectsInfoDecoded.EstStartDate, View_ProjectsInfoDecoded.ProjectStartDate
, View_ProjectsInfoDecoded.ProjectCompletionDate, View_ProjectsInfoDecoded.Complexity
, View_ProjectsInfoDecoded.ProjectType, View_ProjectsInfoDecoded.VoidInd
, View_ProjectsBuilderInfoDecoded.ProjectHealth, View_ProjectsBuilderInfoDecoded.PrimaryBuilder
, View_ProjectsBuilderInfoDecoded.CurrentProjectStatus, PMTT_DailyTime.VoidInd
, DatePart("yyyy", PMTT_DailyTime.ReportDate), PMTT_DailyTime.Time
I think this is an easy fix in the Group function or the type of joins used. But not sure...
With a re-factoring of your query to use aliases, include line breaks and re-order columns, you will notice you have two additional GROUP BY fields that are not included in SELECT: EstStartDate and p.Complexity. As a result, the SELECT columns may show repeated values over the distinct groupings of these omitted two fields.
For a more readable aggregate query, consider including the same columns in GROUP BY also in SELECT clause without omitting any. Do note: per SQL standard, you cannot have a column in SELECT that does not appear in GROUP BY. However, the reverse as your query does is valid. Alternatively, simply run the analogous SELECT DISTINCT without GROUP BY.
SELECT p.ProjectNbr, p.Department, p.ProjectDesc, p.ProjectStartDate, p.ProjectCompletionDate,
p.VoidInd, p.ProjectStatus, p.ProjectType, DatePart("yyyy", d.ReportDate) AS [ReportYear],
d.Time, d.VoidInd, b.ProjectHealth, b.PrimaryBuilder, b.CurrentProjectStatus
FROM (View_ProjectsInfoDecoded p
LEFT JOIN View_ProjectsBuilderInfoDecoded b
ON (p.Department = b.Department) AND (p.ProjectNbr = b.ProjectNbr))
LEFT JOIN PMTT_DailyTime d
ON (b.Department = d.Department) AND (b.ProjectNbr = d.ProjectNbr)
WHERE (p.Department IN ('107'))
AND (p.ProjectStatus <> 'Cancel')
AND (dbo.p.VoidInd = 'N' OR dbo.p.VoidInd IS NULL)
AND (d.VoidInd = 'N' OR d.VoidInd IS NULL)
AND ((DATEDIFF(MONTH, p.ProjectCompletionDate, GETDATE()) <= 12)
OR (p.ProjectCompletionDate IS NULL)
OR (p.ProjectCompletionDate='')
)
GROUP BY p.ProjectNbr, p.Department, p.ProjectDesc, p.ProjectStartDate, p.ProjectCompletionDate,
p.VoidInd, p.ProjectStatus, p.ProjectType, DatePart("yyyy", d.ReportDate),
d.Time, d.VoidInd, b.ProjectHealth, b.PrimaryBuilder, b.CurrentProjectStatus,
p.EstStartDate, p.Complexity -- ADDITIONAL NON-SELECT FIELDS
You are using the Group By clause, but have no aggregate function in your Select statement. This results in the same behavior as using Select Distinct. Removing the Group By clause will include the duplicate records you seem to be looking for.
SELECT View_ProjectsInfoDecoded.ProjectNbr, View_ProjectsInfoDecoded.Department, View_ProjectsInfoDecoded.ProjectDesc, View_ProjectsInfoDecoded.ProjectStartDate, View_ProjectsInfoDecoded.ProjectCompletionDate, View_ProjectsInfoDecoded.VoidInd, View_ProjectsInfoDecoded.ProjectStatus, View_ProjectsInfoDecoded.ProjectType, DatePart("yyyy", PMTT_DailyTime.ReportDate) AS [ReportYear], PMTT_DailyTime.Time, PMTT_DailyTime.VoidInd, View_ProjectsBuilderInfoDecoded.ProjectHealth, View_ProjectsBuilderInfoDecoded.PrimaryBuilder, View_ProjectsBuilderInfoDecoded.CurrentProjectStatus
FROM (View_ProjectsInfoDecoded LEFT JOIN View_ProjectsBuilderInfoDecoded ON (View_ProjectsInfoDecoded.Department = View_ProjectsBuilderInfoDecoded.Department) AND (View_ProjectsInfoDecoded.ProjectNbr = View_ProjectsBuilderInfoDecoded.ProjectNbr)) LEFT JOIN
PMTT_DailyTime ON (View_ProjectsBuilderInfoDecoded.Department = PMTT_DailyTime.Department) AND (View_ProjectsBuilderInfoDecoded.ProjectNbr= PMTT_DailyTime.ProjectNbr)
WHERE (View_ProjectsInfoDecoded.Department IN ('107')) And (View_ProjectsInfoDecoded.ProjectStatus <>'Cancel') And
(dbo.View_ProjectsInfoDecoded.VoidInd = 'N' OR dbo.View_ProjectsInfoDecoded.VoidInd IS NULL) AND (PMTT_DailyTime.VoidInd = 'N' OR PMTT_DailyTime.VoidInd IS NULL)
AND ((DATEDIFF(MONTH, View_ProjectsInfoDecoded.ProjectCompletionDate,GETDATE()) <= 12) OR (View_ProjectsInfoDecoded.ProjectCompletionDate IS NULL) OR (View_ProjectsInfoDecoded.ProjectCompletionDate='' ))

Combine 2 complex queries into 1

I am trying to figure out if there's a way to combine these 2 queries into a single one. I've run into the limits of what I know and can't figure out if this is possible or not.
This is the 1st query that gets last year sales for each day per location (for one month):
if object_id('tempdb..#LY_Data') is not null drop table #LY_Data
select
[LocationId] = ri.LocationId,
[LY_Date] = convert(date, ri.ReceiptDate),
[LY_Trans] = count(distinct ri.SalesReceiptId),
[LY_SoldQty] = convert(money, sum(ri.Qty)),
[LY_RetailAmount] = convert(money, sum(ri.ExtendedPrice)),
[LY_NetSalesAmount] = convert(money, sum(ri.ExtendedAmount))
into #LY_Data
from rpt.SalesReceiptItem ri
join #Location l
on ri.LocationId = l.Id
where ri.Ignored = 0
and ri.LineType = 1 /*Item*/
and ri.ReceiptDate between #_LYDateFrom and #_LYDateTo
group by
ri.LocationId,
ri.ReceiptDate
Then the 2nd query computes a ratio based on the total sales for that month for each day (to be used later):
if object_id('tempdb..#LY_Data2') is not null drop table #LY_Data2
select
[LocationId] = ly.LocationId,
[LY_Date] = ly.LY_Date,
[LY_Trans] = ly.LY_Trans,
[LY_RetailAmount] = ly.LY_RetailAmount,
[LY_NetSalesAmount] = ly.LY_NetSalesAmount,
[Ratio] = ly.LY_NetSalesAmount / t.MonthlySales
into #LY_Data2
from (
select
[LocationId] = ly.LocationId,
[MonthlySales] = sum(ly.LY_NetSalesAmount)
from #LY_Data ly
group by
ly.LocationId
) t
join #LY_Data ly
on t.LocationId = ly.LocationId
I've tried using the first query as a subquery in the 2nd query group-by from clause, but that won't let me select those columns in the outer most select statement (multi part identifier couldn't be bound).
As well as putting the first query into the join clause at the end of the 2nd query with the same issue.
There's probably something I'm missing, but I'm still pretty new to SQL so any help or just a pointer in the right direction would be greatly appreciated! :)
You can try using a Common Table Expression (CTE) and window function:
if object_id('tempdb..#LY_Data') is not null drop table #LY_Data
;with
cte AS
(
select
[LocationId] = ri.LocationId,
[LY_Date] = convert(date, ri.ReceiptDate),
[LY_Trans] = count(distinct ri.SalesReceiptId),
[LY_SoldQty] = convert(money, sum(ri.Qty)),
[LY_RetailAmount] = convert(money, sum(ri.ExtendedPrice)),
[LY_NetSalesAmount] = convert(money, sum(ri.ExtendedAmount))
from rpt.SalesReceiptItem ri
join #Location l
on ri.LocationId = l.Id
where ri.Ignored = 0
and ri.LineType = 1 /*Item*/
and ri.ReceiptDate between #_LYDateFrom and #_LYDateTo
group by
ri.LocationId,
ri.ReceiptDate
)
select
[LocationId] = cte.LocationId,
[LY_Date] = cte.LY_Date,
...
[Ratio] = cte.LY_NetSalesAmount / sum(cte.LY_NetSalesAmount) over (partition by cte.LocationId)
into #LY_Data
from cte
sum(cte.LY_NetSalesAmount) over (partition by cte.LocationId) gives you the sum for each locationId. The code assume that this sum is always non-zero. Otherwise, a divide-by-0 error will occur.
Seems like all you need to do is calculate ratio in the first query.
You can do this with a correlated subquery.
SELECT
...
convert(money, sum(ri.ExtendedAmount)/(SELECT sum(ri2.ExtendedAmount)
FROM rpt.SalesReceiptItem ri2
WHERE ri2.LocationId=ri.LocationId
)
) AS ratio --extended amount/total extended amount for this location

Adding a new computed variable back to main dataset in SQL

I am trying to compute a variable (say last_week) and add it back to my main dataset (say new_j). I managed to join it to new_j. However, if I want to use that variable (last_week) now for further calculations, it does not recognise it. Here's my code:
SELECT [Weekkey] AS weekkey
,[article / colour] as prod_id
,[Current MP Department No/Desc] as prod_dept
,[Total Stock] as total_stock
INTO #new_j
FROM [J_20160831] --(that’s the db in server and I created a temp db #new_j)
SELECT prod_id, max(weekkey) as last_week
into #lastweeksales
FROM #new_j
group by prod_id
select *
from #new_j
left join #lastweeksales
on #lastweeksales.prod_id = #new_j.prod_id
So, I joined both successfully and if I run this code, I see column last_week. Now what I want to do is this:
select *
,case
when last_week = max(weekkey) then total_stock
else 0
end as last_stock_position
from #new_j
But it says last_week is not found in new_j. I also tried #lastweeksales.last_week instead of just last_week in the last bit of code, but it didn't either. What's the best way out here? Moreover, is there a better way to do it instead?. The output I am looking to have at the end is a table with these variables: WeekKey, prod_dept, prod_id, total_stock, last_week, last_stock_position
Thanks for the help!!! Much appreciate it.
This normal behaviour of joins..
by selecting this
select * from #new_j left join #lastweeksales
on #lastweeksales.prod_id = #new_j.prod_id'
all the columns of newj and lastweekales will be displayed in same order (first new_j columns and then lastweeksales columns ).So 'last_week' is the last column of lastweeksales.
Secondly,
select *,
case when last_week = max(weekkey) then total_stock
else 0
end as last_stock_position
from #new_j
in above query,your are selecting 'last_week' column which belongs to the table #lastweeksales.
Be careful while selecting the columns.
I guess your expecting,
select a.WeekKey, a.prod_dept, a.prod_id, a.total_stock, b.last_week,
case
when b.last_week = max(a.weekkey) then total_stock
else 0
end as last_stock_position
from #new_j as a
left join #lastweeksales as b
on b.prod_id = a.prod_id
group by a.weekkey,a.prod_dept,a.prod_id,a.total_stock,b.last_week

SQL issue with NULL values on SUM

I'm currently working on some sql stuff, but running in a bit of an issue.
I've got this method that looks for cash transactions, and takes off the cashback but sometimes there are no cash transactions, so that value turns into NULL and you can't subtract from NULL.
I've tried to put an ISNULL around it, but it still turns into null.
Can anyone help me with this?
;WITH tran_payment AS
(
SELECT 1 AS payment_method, NULL AS payment_amount, null as tran_header_cid
UNION ALL
SELECT 998 AS payment_method, 2 AS payment_amount, NULL as tran_header_cid
),
paytype AS
(
SELECT 1 AS mopid, 2 AS mopshort
),
tran_header AS
(
SELECT 1 AS cid
)
SELECT p.mopid AS mopid,
p.mopshort AS descript,
payment_value AS PaymentValue,
ISNULL(DeclaredValue, 0.00) AS DeclaredValue
from paytype p
LEFT OUTER JOIN (SELECT CASE
When (tp.payment_method = 1)
THEN
(ISNULL(SUM(tp.payment_amount), 0)
- (SELECT ISNULL(SUM(ABS(tp.payment_amount)), 0)
FROM tran_payment tp
INNER JOIN tran_header th on tp.tran_header_cid = th.cid
WHERE payment_method = 998
) )
ELSE SUM(tp.payment_amount)
END as payment_value,
tp.payment_method,
0 as DeclaredValue
FROM tran_header th
LEFT OUTER JOIN tran_payment tp
ON tp.tran_header_cid = th.cid
GROUP BY payment_method) pmts
ON p.mopid = pmts.payment_method
Maybe COALESCE() can help you?
You can try this:
SUM(COALESCE(tp.payment_amount, 0))
or
COALESCE(SUM(tp.payment_amount), 0)
COALESCE(arg1, arg2, ..., argN) returns the first non-null argument from the list.
try to put ISNULL inside SUM and ABS, i.e. around the actual field, like this
SUM(ISNULL(tp.payment_amount, 0))
SUM(ABS(ISNULL(tp.payment_amount, 0)))
I don't have MS SQL to test here, but would it work to put the ISNULL around the SELECT? Maybe, ISNULL isn't triggered at all, if there are no matching rows...