How to replace a NULL when a COUNT(*) returns NULL in DB2 - sql

I have a query:
SELECT A.AHSHMT AS SHIPMENT, A.AHVNAM AS VENDOR_NAME, D.UNITS_SHIPPED, D.ADPON AS PO, B.NUMBER_OF_CASES_ON_TRANSIT, C.NUMBER_OF_CASES_RECEIVED FROM AHASNF00 A
INNER JOIN (SELECT IDSHMT, COUNT(*) AS NUMBER_OF_CASES_ON_TRANSIT FROM IDCASE00 WHERE IDSTAT = '01' GROUP BY IDSHMT) B
ON (A.AHSHMT = B.IDSHMT)
LEFT JOIN (SELECT IDSHMT, (COUNT(*) AS NUMBER_OF_CASES_RECEIVED FROM IDCASE00 WHERE IDSTAT = '10' GROUP BY IDSHMT) C
ON (A.AHSHMT = C.IDSHMT)
INNER JOIN (SELECT ADSHMT, ADPON, SUM(ADUNSH) AS UNITS_SHIPPED FROM ADASNF00 GROUP BY ADSHMT, ADPON) D
ON (A.AHSHMT = D.ADSHMT)
WHERE A.AHSHMT = '540041134';
On the first JOIN statement I have a COUNT(*), on this count sometimes I will get NULL. I need to replace this with a "0-zero", I know think I know how to do it in SQL
ISNULL(COUNT(*), 0)
But this doesn't work for DB2, how can I accomplish this? All your help is really appreciate it.

Wrap a COALESCE around each of the nullable totals in your SELECT list:
SELECT A.AHSHMT AS SHIPMENT,
A.AHVNAM AS VENDOR_NAME,
COALESCE( D.UNITS_SHIPPED, 0 ) AS UNITS_SHIPPED,
D.ADPON AS PO,
COALESCE( B.NUMBER_OF_CASES_ON_TRANSIT, 0 ) AS NUMBER_OF_CASES_ON_TRANSIT,
COALESCE( C.NUMBER_OF_CASES_RECEIVED, 0 ) AS NUMBER_OF_CASES_RECEIVED
FROM ...
The inner joins you're using for expressions B and D mean that you will only receive rows from A that have one or more cases in transit (expression B) and have one or more POs in expression D. Is that the way you want your query to work?

Instead of using ISNULL(COUNT(*), 0),
try using COALESCE(COUNT(*),0)

use IFNULL(COUNT(*), 0) for DB2

Related

How to force postgres to return 0 even if there are no rows matching query, using coalesce, group by and join

I've been trying hopelessly to get the following SQL statement to return the query results and default to 0 if there are no rows matching the query.
This is the intended result:
vol | year
-------+------
0 | 2018
Instead I get:
vol | year
-----+------
(0 rows)
Here is the sql statement:
select coalesce(vol,0) as vol, year
from (select sum(vol) as vol, year
from schema.fact_data
join schema.period_data
on schema.fact_data.period_tag = schema.period_data.tag
join schema.product_data
on schema.fact_data.product_tag =
schema.product_data.tag
join schema.market_data
on schema.fact_data.market_tag = schema.market_data.tag
where "retailer"='MadeUpRetailer'
and "product_tag"='FakeProductTag'
and "year"='2018' group by year
) as DerivedTable;
I know the query works because it returns data when there is data. Just doesn't default to 0 as intended...
Any help in finding why this is the case would be much appreciated!
Using your subquery DerivedTable, you could write:
SELECT coalesce(DerivedTable.vol, 0) AS vol,
y.year
FROM (VALUES ('2018'::text)) AS y(year)
LEFT JOIN (SELECT ...) AS DerivedTable
ON DerivedTable.year = y.year;
Remove the GROUP BY (and the outer query):
select 2018 as year, coalesce(sum(vol), 0) as vol
from schema.fact_data f join
schema.period_data p
on f.period_tag = p.tag join
schema.product_data pr
on f.product_tag = pr.tag join
schema.market_data m
on fd.market_tag = m.tag
where "retailer" = 'MadeUpRetailer' and
"product_tag" = 'FakeProductTag' and
"year" = '2018';
An aggregation query with no GROUP BY always returns exactly one row, so this should do what you want.
EDIT:
The query would look something like this:
select v.yyyy as year, coalesce(sum(vol), 0) as vol
from (values (2018), (2019)) v(yyyy) left join
schema.fact_data f
on f.year = v.yyyy left join -- this is just an example. I have no idea where year is coming from
schema.period_data p
on f.period_tag = p.tag left join
schema.product_data pr
on f.product_tag = pr.tag left join
schema.market_data m
on fd.market_tag = m.tag
group by v.yyyy
However, you have to move the where conditions to the appropriate on clauses. I have no idea where the columns are coming from.
From the code you posted it is not clear in which table you have the year column.
You can use UNION to fetch just 1 row in case there are no rows in that table for the year 2018 like this:
select sum(vol) as vol, year
from schema.fact_data innrt join schema.period_data
on schema.fact_data.period_tag = schema.period_data.tag
inner join schema.product_data
on schema.fact_data.product_tag = schema.product_data.tag
inner join schema.market_data
on schema.fact_data.market_tag = schema.market_data.tag
where
"retailer"='MadeUpRetailer' and
"product_tag"='FakeProductTag' and
"year"='2018'
group by "year"
union
select 0 as vol, '2018' as year
where not exists (
select 1 from tablename where "year" = '2018'
)
In case there are rows for the year 2018, then nothing will be fetched by the 2nd query,

Aggregate function results in select statement

Hopefully the code below should demonstrate what I'm trying to achieve.
The issue is that none of the input selects are resolved by the time I try to calculate VatableCash so I get "Invalid Column" when trying to select it.
Sorry if there's something plainly obvious I can do here. SQL isn't one of my strong suits.
select
OrderHeader.ID,
sum(OrderLine.NetPrice) as OrderLineNetPrice,
sum(OrderLine.GrossPrice) as OrderLineGrossPrice,
sum(
case when PaymentOption_ID = 8
then Payment.Amount
else 0
end
) as TotalCashAmount,
((OrderLineGrossPrice - OrderLineNetPrice) / OrderLineGrossPrice) * TotalCashAmount as VatableCash
from OrderHeader
inner join Payment on Payment.OrderHeader_ID = OrderHeader.ID
inner join OrderLine on OrderLine.OrderHeader_ID = OrderHeader.ID
group by OrderHeader.ID
You need to use sub query.
you can try this.
;WITH CTE AS
(
select
OrderHeader.ID,
sum(OrderLine.NetPrice) as OrderLineNetPrice,
sum(OrderLine.GrossPrice) as OrderLineGrossPrice,
sum(
case when PaymentOption_ID = 8
then Payment.Amount
else 0
end
) as TotalCashAmount
from OrderHeader
inner join Payment on Payment.OrderHeader_ID = OrderHeader.ID
inner join OrderLine on OrderLine.OrderHeader_ID = OrderHeader.ID
group by OrderHeader.ID
)
SELECT *,
((OrderLineGrossPrice - OrderLineNetPrice) / OrderLineGrossPrice) * TotalCashAmount as VatableCash
FROM CTE
Love the cross apply! Use it whenever you want some handy extra columns.
select
OrderHeader.ID,
sum(OrderLine.NetPrice) as OrderLineNetPrice,
sum(OrderLine.GrossPrice) as OrderLineGrossPrice,
TotalCashAmount,
((OrderLineGrossPrice - OrderLineNetPrice) / OrderLineGrossPrice) * TotalCashAmount as VatableCash
from OrderHeader
inner join Payment on Payment.OrderHeader_ID = OrderHeader.ID
inner join OrderLine on OrderLine.OrderHeader_ID = OrderHeader.ID
cross apply ( select sum(
case when PaymentOption_ID = 8
then Payment.Amount
else 0
end
)) as subquery(TotalCashAmount)
group by OrderHeader.ID

AVG of SUM in SQL

Here's my code:
SELECT B1_COD, SB1030.B1_DESC, B2_CM1, B2_QATU, SUM (B2_QATU)
FROM SB1030
INNER JOIN SB2030 ON B1_COD = B2_COD
WHERE (B1_TIPO='PA') AND (B2_QATU <> '0')
I'd like to:
multiply b2_cm1 by b2_qatu creating b2_VAL
sum all b2_qatu with same b1_cod creating b2_SAL
divide b2_VAL by b2_SAL
Could anyone help me?????
Thanks
Here is what I think you are looking for. A list of b1_cods with sums and a calculation based on the sums.
select
b1_cod,
sb1030.b1_desc,
sum(b2_cm1) as sum_cm1,
sum(b2_qatu) as b2_sal,
sum(b2_qatu * b2_cm1) as b2_val,
sum(b2_qatu) / sum(b2_qatu * b2_cm1) as new_field
from sb1030
inner join sb2030 on b1_cod = b2_cod
where b1_tipo = 'pa' and b2_qatu <> '0'
group by b1_cod, sb1030.b1_desc
order by b1_cod, sb1030.b1_desc;
Do you only want the result b2_VAL and b2_SAL?
Try using WITH CTE:
WITH CTE AS(
SELECT SUM(B1_COD) AS B1_COD, SB1030.B1_DESC,B2_CM1*B2_QATU AS b2_VAL, SUM (B2_QATU) AS B2_QATU
FROM SB1030
INNER JOIN SB2030 ON B1_COD = B2_COD
WHERE (B1_TIPO='PA') AND (B2_QATU <> '0'))
SELECT B1_COD+B2_QATU, b2_VAL
FROM CTE
Is it something like that you are looking for?

Column is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause

Ok here's my View (vw_LiftEquip)
SELECT dbo.tbl_equip_swl_unit.unit_id,
dbo.tbl_equip_swl_unit.unit_name,
dbo.tbl_equip_swl_unit.archived,
dbo.tbl_categories.category_id,
dbo.tbl_categories.categoryName,
dbo.tbl_categories.parentCategory,
dbo.tbl_categories.sub_category,
dbo.tbl_categories.desc_category,
dbo.tbl_categories.description,
dbo.tbl_categories.miscellaneous,
dbo.tbl_categories.category_archived,
dbo.tbl_equip_swl_unit.unit_name AS Expr1,
dbo.tbl_categories.categoryName AS Expr2,
dbo.tbl_categories.description AS Expr3,
dbo.tbl_equip_depts.dept_name,
dbo.tbl_equip_man.man_name,
dbo.tbl_Lifting_Gear.e_defects AS Expr7,
dbo.tbl_Lifting_Gear.e_defects_desc AS Expr8,
dbo.tbl_Lifting_Gear.e_defects_date AS Expr9,
dbo.tbl_equipment.equipment_id,
dbo.tbl_equipment.e_contract_no,
dbo.tbl_equipment.slID,
dbo.tbl_equipment.e_entered_by,
dbo.tbl_equipment.e_serial,
dbo.tbl_equipment.e_model,
dbo.tbl_equipment.e_description,
dbo.tbl_equipment.e_location_id,
dbo.tbl_equipment.e_owner_id,
dbo.tbl_equipment.e_department_id,
dbo.tbl_equipment.e_manafacture_id,
dbo.tbl_equipment.e_manDate1,
dbo.tbl_equipment.e_manDate2,
dbo.tbl_equipment.e_manDate3,
dbo.tbl_equipment.e_dimensions,
dbo.tbl_equipment.e_test_no,
dbo.tbl_equipment.e_firstDate1,
dbo.tbl_equipment.e_firstDate2,
dbo.tbl_equipment.e_firstDate3,
dbo.tbl_equipment.e_prevDate1,
dbo.tbl_equipment.e_prevDate2,
dbo.tbl_equipment.e_prevDate3,
dbo.tbl_equipment.e_insp_frequency,
dbo.tbl_equipment.e_swl,
dbo.tbl_equipment.e_swl_unit_id,
dbo.tbl_equipment.e_swl_notes,
dbo.tbl_equipment.e_cat_id,
dbo.tbl_equipment.e_sub_id,
dbo.tbl_equipment.e_parent_id,
dbo.tbl_equipment.e_last_inspector,
dbo.tbl_equipment.e_last_company,
dbo.tbl_equipment.e_deleted AS Expr11,
dbo.tbl_equipment.e_deleted_desc AS Expr12,
dbo.tbl_equipment.e_deleted_date AS Expr13,
dbo.tbl_equipment.e_deleted_insp AS Expr14,
dbo.tbl_Lifting_Gear.e_defects_action AS Expr15,
dbo.tbl_equipment.e_rig_location,
dbo.tbl_Lifting_Gear.e_add_type AS Expr17,
dbo.tbl_Lifting_Gear.con_id,
dbo.tbl_Lifting_Gear.lifting_date,
dbo.tbl_Lifting_Gear.lifting_ref_no,
dbo.tbl_Lifting_Gear.e_id,
dbo.tbl_Lifting_Gear.inspector_id,
dbo.tbl_Lifting_Gear.lift_testCert,
dbo.tbl_Lifting_Gear.lift_rig_location,
dbo.tbl_Lifting_Gear.inspected,
dbo.tbl_Lifting_Gear.lifting_through,
dbo.tbl_Lifting_Gear.liftingNDT,
dbo.tbl_Lifting_Gear.liftingTest,
dbo.tbl_Lifting_Gear.e_defects,
dbo.tbl_Lifting_Gear.e_defects_desc,
dbo.tbl_Lifting_Gear.e_defects_date,
dbo.tbl_Lifting_Gear.e_defects_action,
dbo.tbl_Lifting_Gear.lift_department_id,
dbo.tbl_Lifting_Gear.lifting_loc
FROM dbo.tbl_equipment
INNER JOIN dbo.tbl_equip_swl_unit
ON dbo.tbl_equipment.e_swl_unit_id = dbo.tbl_equip_swl_unit.unit_id
INNER JOIN dbo.tbl_categories
ON dbo.tbl_equipment.e_cat_id = dbo.tbl_categories.category_id
INNER JOIN dbo.tbl_equip_depts
ON dbo.tbl_equipment.e_department_id = dbo.tbl_equip_depts.dept_id
INNER JOIN dbo.tbl_equip_man
ON dbo.tbl_equipment.e_manafacture_id = dbo.tbl_equip_man.man_id
INNER JOIN dbo.vwSubCategory
ON dbo.tbl_equipment.e_sub_id = dbo.vwSubCategory.category_id
INNER JOIN dbo.vwDescCategory
ON dbo.tbl_equipment.e_cat_id = dbo.vwDescCategory.category_id
INNER JOIN dbo.tbl_Lifting_Gear
ON dbo.tbl_equipment.equipment_id = dbo.tbl_Lifting_Gear.e_id
And here's the select statement with subquery that I am using:
SELECT *
FROM vw_LiftEquip
WHERE lifting_loc = ? AND
con_id = ? AND
EXPR11 =
'N'(
SELECT MAX(lifting_date) AS maxLift
FROM vw_LiftEquip
WHERE e_id = equipment_id
)
ORDER BY lifting_ref_no,
category_id,
e_swl,
e_serial
I get the error :
Column "vw_LiftEquip.category_id" is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause.
Can't see why its returning that error, this is admittedly the first time I've ran a subquery on such a complex view, and I am a bit lost, thanks in advance for any help. I have looked through the similar posts and can find no answers to this one, sorry if I am just being dumb.
You are missing AND between EXPR11 = 'N' and (SELECT MAX(...
Otherwise, it looks OK. MAX without GROUP BY is allowed if you have no other columns in the SELECT
Update: #hvd also noted that you have nothing to compare to MAX(lifting_date). See comment
Update 2,
SELECT *
FROM vw_LiftEquip v1
CROSS JOIN
(
SELECT MAX(lifting_date) AS maxLift
FROM vw_LiftEquip
WHERE e_id = equipment_id
) v2
WHERE v1.lifting_loc = ? AND
v1.con_id = ? AND
v1.EXPR11 = 'N'
ORDER BY v1.lifting_ref_no,
v1.category_id,
v1.e_swl,
v1.e_serial

Oracle SELECT help

Here is my SELECT query:
SELECT
a.id_auto,
SUM(pozicane_dni * a.poplatok_denny + najazdene_km * a.poplatok_km) celkova_trzba
FROM Auta a
INNER JOIN (SELECT
id_auto,
(SUM(koniec_pozicania - zaciatok_pozicania)) pozicane_dni,
(SUM(najazdene_km)) najazdene_km,
zaloha
FROM Zakaznik GROUP BY id_auto) z
ON z.id_auto = a.id_auto
INNER JOIN (SELECT
id_auto,
poplatok_denny,
poplatok_km
FROM Auta_zaloha) az
ON az.id_auto = a.id_auto
GROUP BY a.id_auto;
But I'm getting this error:
ORA-00979: not a GROUP BY expression
Anybody knows where could be the problem? I'm a little bit confused. I have GROUP BY clause everywhere where I use aggregate function SUM().
EDIT:
One more thing, it stop working when I add a CASE WHEN to the query:
SELECT
a.id_auto, a.poplatok_denny, a.poplatok_km,
CASE WHEN z.zaloha IS NULL THEN
(pozicane_dni * a.poplatok_denny + najazdene_km * a.poplatok_km)
ELSE
(pozicane_dni * az.poplatok_denny + najazdene_km * az.poplatok_km)
END
celkova_trzba
FROM Auta a
INNER JOIN (SELECT
id_auto,
(SUM(koniec_pozicania - zaciatok_pozicania)) pozicane_dni,
(SUM(najazdene_km)) najazdene_km,
zaloha
FROM Zakaznik GROUP BY id_auto, zaloha) z
ON z.id_auto = a.id_auto
INNER JOIN (SELECT
id_auto,
poplatok_denny,
poplatok_km
FROM Auta_zaloha) az
ON az.id_auto = a.id_auto
GROUP BY a.id_auto;
In your first inner SELECT, you should either remove "zaloha", GROUP BY it or apply some aggregate function to it.
The problem will be in using the value of
a.poplatok_km
If you're grouping by a.id_auto, you need to give a rule on what to do if there are multiple rows in the result set (even if there is only one possible row, that is something the SQL doesn't "know").
Two ways around this:
add all columns from table a that are required in the calculation in the group by clause
use a "pseudo-Function" like min (a.poplatok_km) which doesn't change anything
Your second inner select:
INNER JOIN (SELECT
id_auto,
poplatok_denny,
poplatok_km
FROM Auta_zaloha) az
Appears to be missing a group by clause like:
INNER JOIN (SELECT
id_auto,
poplatok_denny,
poplatok_km
FROM Auta_zaloha group by id_auto) az
Try using NVL2 function in place of CASE WHEN, at least it could yield more understandable error message:
NVL2(z.zaloha,
(pozicane_dni * az.poplatok_denny + najazdene_km * az.poplatok_km),
(pozicane_dni * a.poplatok_denny + najazdene_km * a.poplatok_km)
) celkova_trzba