Convert null values to zero in crosstab query - sql

The code below is a subset of a larger code that results in a cross tab query. The issue is that the total column to the right which sums all the number columns in the cross tab query does not calculate accurately as it results a 0 for any rows that have null value in one of the twelve columns it is attempting to sum.
I believe that the i need to add a condition to the following line in the code to result in a zero if the value is null. I just need someone to take a second look at it. If there is a better alternate solution, I am happy to entertain that also.
SUM(entry) for MX in (M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12)
SELECT
tblCenters.prop
,tblAccounts.Category_EXCO
,tblCenters.CenterNum
,tblAccounts.AccountNum
,tblAccounts.Account_Description
,tblAccounts.Is_Revenue
,tblAccounts.Is_Above_EBITDA
,tblCenters.Division_Description
,tblCenters.[Is_F&B1]
,tblCenters.Group_Description
,Entry
,MX
FROM GA_Financial.dbo.tblSAP
left join tblMX on tblSAP.MDY = tblMX.MDY
left join tblAccounts on tblSAP.AccountNum = tblAccounts.AccountNum
left join tblCenters on tblSAP.CenterNum = tblCenters.CenterNum and tblSAP.Prop_SAP = tblCenters.PROP_SAP
WHERE tblAccounts.Is_Above_EBITDA = 1
AND tblSAP.Type = 'A'
)
AS Tab1
--The code below breaks down column "Entry" into twelve individual monthly columns and fills columns M1 through M12
PIVOT
(
SUM(entry) for MX in (M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12)
) as TAb2
where Prop = 'RWNY'

I think that you can use the COALESCE or IFNULL functions to replace the null value with a 0 for the sum calculation. Check out this response: COALESCE, IFNULL, or NZ() function that can be used in SQL Server and MS Access

To avoid a null result use ISNULL(Entry, 0) instead of Entry in your original query. This will substitute any returned null's with 0's.

Related

How to create an additional column in a SQL query that contains the number of rows with a column value equal to a column value from the current row?

This is what I currently have (it doesn't work):
select MOCKSTEMS.WORD_ID,
MOCKSTEMS.STEM_ID,
MOCKSTEMS.LABSTEM,
MOCKSTEMS.LABSTEMCATEGORY,
MOCKLEMMAS.LEMMAFORM,
MOCKSTEMS.LEMMA_ID,
MOCKWORDS.ORIGINALWORD,
MOCKSTEMS.CONTAINEDIN,
COUNT(*) as SAMEVALUE from MOCKSTEMS where CONTAINEDIN=STEM_ID
from MOCKSTEMS
inner join MOCKWORDS on MOCKSTEMS.WORD_ID = MOCKWORDS.WORD_ID
inner join MOCKLEMMAS on MOCKSTEMS.LEMMA_ID = MOCKLEMMAS.LEMMA_ID
Basically, I wish to create a column called 'SAMEVALUE' that shows the number of rows in this query with 'CONTAINEDIN' values equal to the 'STEM_ID' value of each row. Is this possible, and if so, how can I do it with SQL?
EDITED:
This is what I get when I run the query without the 'COUNT(*) as SAMEVALUE from MOCKSTEMS where CONTAINEDIN=STEM_ID' row:
image of a few rows returned by the query.
For example, for the row with STEM_ID='stem-003' and LABSTEM='owotan okitz', I would like the SAMEVALUE column to have value 2, because there are 2 rows with CONTAINEDIN='stem-003', as circled in this image.
It would also be fine if the SAMEVALUE column just indicates true/false (or 0/1) depending on whether there are rows with CONTAINEDIN values equal to the STEM_ID of each row.
To get overall count alongside the query results, you need an analytic function. So to count only rows with some condition, we put this condition in case expression, which returns something in case of "true", and null in other cases. Then count will ignore nulls.
select MOCKSTEMS.WORD_ID,
MOCKSTEMS.STEM_ID,
MOCKSTEMS.LABSTEM,
MOCKSTEMS.LABSTEMCATEGORY,
MOCKLEMMAS.LEMMAFORM,
MOCKSTEMS.LEMMA_ID,
MOCKWORDS.ORIGINALWORD,
MOCKSTEMS.CONTAINEDIN,
COUNT(
case
when CONTAINEDIN=STEM_ID
then 1
end
) over() as SAMEVALUE
/*Over is empty to consider all the result set as a single window*/
from MOCKSTEMS
inner join MOCKWORDS on MOCKSTEMS.WORD_ID = MOCKWORDS.WORD_ID
inner join MOCKLEMMAS on MOCKSTEMS.LEMMA_ID = MOCKLEMMAS.LEMMA_ID

ORA-00909: invalid number of arguments when using NVL

I have a column that gets the specific amount which has a condition like below.
I tried this one to get his specific value but I getting a multiple rows which it should be single row.
select distinct
(case
when aila.line_type_lookup_code = 'ITEM' and aila.tax_classification_code = 'VAT12 SERVICES' then to_char(aila.assessable_value) else '0'
end) as taxable_lines
from
ap_invoice_lines_all aila
where
aila.invoice_id = '31004'
then I tried this one to replace a null values.
select distinct
(case
when aila.line_type_lookup_code = 'ITEM' and aila.tax_classification_code = 'VAT12 SERVICES' then nvl(to_char(aila.assessable_value,0)) end) as taxable_lines
from
ap_invoice_lines_all aila
where
aila.invoice_id = '31004'
For example I have a table named ap_invoice_lines_all that has a columns name
line_type_lookup_code string
tax_classification_code string
assessable_value double
then the expected output I want based on the query I tried above is
taxable lines
1300
but the one I get is
taxable lines
0
1300
How do I remove the 0 in the result?
Thanks!
First off, you are using to_char wrong. This function should only have a single argument in this context:
nvl(to_char(aila.assessable_value,0))
should be
nvl(to_char(aila.assessable_value),0)
I would recommend against using a case expression like this in such a simple query to improve readability. Case expressions are great tools, but typically decrease the query readability. And in this particular instance, you don't really need an IF..THEN..ELSE function (which is the reason to use case expressions).
Secondly, are you sure there is only record where aila.invoice_id = '31004'? The query will only return two rows if there are actually two rows in the table where that clause is true. In this case it finds one row where assessable_value is null and one where it isn't.
In any case, to remove the zero (or in this case a null value) from the resultset, you can simply do this:
select distinct aila.assessable_value as taxable_lines
from ap_invoice_lines_all aila
where aila.invoice_id = '31004'
and aila.line_type_lookup_code = 'ITEM' -- Originally a condition in the case statement
and aila.tax_classification_code = 'VAT12 SERVICES' -- Originally a condition in the case statement
and aila.assessable_value is not null; -- Removes any null values from the result
Or if you want null values to be replaced by a zero;
select distinct nvl(aila.assessable_value, 0) as taxable_lines
from ap_invoice_lines_all aila
where aila.invoice_id = '31004'
and aila.line_type_lookup_code = 'ITEM' -- Originally a condition in the case statement
and aila.tax_classification_code = 'VAT12 SERVICES' -- Originally a condition in the case statement
Note that the distinct clause will cause all rows where assessable_value to be grouped into a single row if multiple rows are a possibility. Remove the distinct clause if you want all rows where assessable_value is null to show in the result as 0.
Lastly, you might want to think about implementing a primary key (if the table doesn't have one) or unique index on invoice_id, if there shouldn't ever be duplicate ids. And it's simply good practice to do so for ID columns which are used often in queries and should be unique.

PostgreSQL where clause not pushed down when using grouping sets

SELECT *
FROM (
SELECT SUM(quantity) AS quantity,
product_location_id,
location_bin_id,
product_lot_id,
product_serial_id,
CASE
WHEN GROUPING (product_location_id, location_bin_id, product_lot_id, product_serial_id) = 0 AND product_serial_id IS NOT NULL THEN
'Serial'
WHEN GROUPING (product_location_id, location_bin_id, product_lot_id, product_serial_id) = 0 THEN
'Lot'
ELSE
'Quantity'
END AS pick_by
FROM product_location_bins
WHERE status != 'Void'
AND has_quantity = 'Yes'
GROUP BY GROUPING SETS (
(product_location_id, location_bin_id, product_lot_id, product_serial_id),
(product_location_id, location_bin_id)
)
HAVING SUM(quantity) > 0
) x
WHERE x.product_serial_id = 5643
I have the above query. Using a normal GROUP BY postgres is able to "push down" the outer where clause and use the index on product_serial_id. When I use grouping sets it's unable to do so. It resolves the entire inner query and then filters the results. I'm wondering why this is. Is it a limitation with grouping sets?
Your query is odd. Your outer where clause eliminates the second set of results from grouping sets, because product_serial_id would be NULL for the second set. This gets filtered out in the outer where.
I think you want something like this for the outer query:
WHERE x.product_serial_id = 5643 OR x.product_serial_id IS NULL
I suppose that Postgres could add optimizations for poorly written code -- that is, eliminate the work for the second grouping sets set because it is filtered out by the outer where. However, that is not usually the focus of optimizations.

Complex Calculation - SQL Server

I'm currently working on calculating a larger set of data with a number of joins and the end result is a calculation across two tables. My current script looks like the following:
USE db1
Go
SELECT
customer, tb1.custid
FROM
[dbo].[tb1]
LEFT OUTER JOIN
[dbo].[tb2] ON tb1.custid = tb2.custid
LEFT OUTER JOIN
[dbo].[tb3] ON tb2.custnumber = tb3.custnumber
LEFT OUTER JOIN
[dbo].[tb4] ON tb2.custid = tb4.custid
WHERE
tb1.custclass = 'non-person'
AND tb4.zip IN ('11111', '11112')
GO
As you can see, it's not the cleanest, but it's working for gathering initial information. The reasoning for the number of joins is due to an incredibly odd table structure I did not create and the fact that the numerical data I need is only stored in tb3.
What I'm now trying to do is calculate the sum of 3 fields from tb3 that are all set as numeric fields and do an AND/OR comparison against a 4th field (also numeric). I know I can SUM them together, but I'm hoping for some input on three things:
Where to place that SUM calculation in the query?
Where to place and how to do the comparison of the SUM total against the 4th field?
Is it possible to return the higher of the two values to a TOTAL column in the initial SELECT?
Thank you in advance.
Where to place that SUM calculation in the query?
If you want it output, you probably want to just add it to the SELECT
SELECT
customer, tb1.custid
(tb3.col1 + tb3.col2 + tb3.col3) as Sum
FROM
...
Where to place and how to do the comparison of the SUM total against the 4th field?
You probably want to do this with a CASE statement, and this also answers your last question
Is it possible to return the higher of the two values to a TOTAL column in the initial SELECT?
SELECT
customer, tb1.custid
CASE WHEN (tb3.col1 + tb3.col2 + tb3.col3) > tb3.col4
THEN (tb3.col1 + tb3.col2 + tb3.col3)
ELSE tb3.col4
END as Total
FROM
...
You should be able to calculate the sum as a nested query:
SELECT (field1 + field2 + field3) AS fields_sum FROM tb3 (...)
Then in your main query you could do something like:
SELECT customer, tb1.custid, (CASE WHEN fields_sum > fourth_field THEN fields_sum ELSE fourth_field END) AS TOTAL (...)

How would I join a value of zero when a left join doesn't match?

I'm looking to join the field Count from the query qCallCount to the results of the query qCustomers. I think I want to use a left join because there are customers in the qCustomers dataset that won't have a match in the qCallCount dataset, but I don't want to drop them from the results.
My current query...
SELECT a.CustomerID, b.Count, a.Customer_Segmentation
FROM qCustomers AS a LEFT JOIN qCallCount AS b ON a.CustomerID=b.CustomerID;
My question is, is there a way to make the value for the Count field in the result of this query have a value of 0 if there's no match in qCallCount?
If this was Excel I'd write an =IFERROR(VLOOKUP(CustomerID, qCallCount, Count, False),0)
Why do I need this? I'm ultimately going to run an average of count avg(Count) as Average and it's important for those failed matches to be treated as zero, because that's what they actually are.
Thanks!
Check null value in MS Access Query
You can check for IsNull(b.Count, 0)
Is Count the name of a column, or are you using the function Count?
The VB/VBA/MS Access null-coalescing function is Nz. (In VB6, IsNull is not the same as in SQL Server--it's a different function that returns a Boolean indicating whether the value is Null.) So it would look like this:
SELECT
a.CustomerID,
Nz(b.Count, 0) AS CallCount,
a.Customer_Segmentation
FROM
qCustomers AS a
LEFT JOIN qCallCount AS b ON a.CustomerID=b.CustomerID;