How to calculate an average in SQL excluding zeroes? - sql

I want to calculate the average of a column of numbers, but i want to exclude the rows that have a zero in that column, is there any way this is possible?
The code i have is just a simple sum/count:
SELECT SUM(Column1)/Count(Column1) AS Average
FROM Table1

SELECT AVG(Column1) FROM Table1 WHERE Column1 <> 0

One approach is AVG() and CASE/NULLIF():
SELECT AVG(NULLIF(Column1, 0)) as Average
FROM table1;
Average ignores NULL values. This assumes that you want other aggregations; otherwise, the obvious choice is filtering.

Multiple roads lead to Rome...
select sum(Column1) / sum( case Column1
case 0 then 0 else 1
end )
from table1

SELECT AVG(column) FROM TABLE
where column **not like** '0%'

Related

How to delete 0 values but not blanks from a column in SQL Server 2008 programming?

I am trying to find the average of a column. I want to remove the 0 values but keep the blanks using SQL Server 2008 programming. Please help
Use AVG()
If you wish to ignore the 0 and include "blank" (if you mean NULL) to the base, you can make use of the following characteristic of the function:
AVG () computes the average of a set of values by dividing the sum of those values by the count of nonnull values.
So that
SELECT AVG(
CASE WHEN [column] = 0 THEN NULL -- Skip 0 when calculate the average
WHEN [column] IS NULL THEN 0 -- Include blank as 0 value
ELSE [column] END) AS Average
FROM [table]
Something like this I guess:
select sum(distinct t1.val)/( count(distinct t2.id)+ count(distinct t3.id))
from mytable t1
join mytable t2
on 1=1
join mytable t3
on 1=1
where not t2.val = 0 and (t3.val is null)
SQLFIDDLE

How to use CASE without adding new column to table in SQL

How to change column value by CASE command depending on condition without giving adding a new column to table?
The only way I know is by adding new column:
SELECT
t1.*
,CASE
what='costs' THEN amount*(-1)
ELSE
sales
END AS NewAmount
FROM t1
Is there a way to get the results as on the picture below? Note that sometimes the condition is specified by values in more than one column (what=costs AND country=Atlantida)
Select just the columns that you want:
SELECT t1.what,
(CASE WHEN what = 'costs' THEN amount*(-1)
ELSE sales
END) AS Amount
FROM t1
Yes, there is way,
Instead of select *, use required column names only.
SELECT
t1.what
,CASE
WHEN what='costs' THEN amount*(-1)
ELSE
sales
END AS Amount
FROM t1
Don't you want amount when not cost?
SELECT
t1.*
,CASE when what='costs' THEN amount*(-1)
ELSE
amount
END AS NewAmount
FROM t1

two query results in datetime compare in sql

I have two sql queries.
SELECT
DATE_FIRST_TABLE
FROM
FIRST_TABLE
and
SELECT
DATE_SECOND_TABLE
FROM
SECOND_TABLE
The above two queries may return single or multiple records.
I need to check the second query results if any date value is greater than any of the date value of first query results then it will evaluate true.
I need some suggestion on this.
Thanks.
Is this what you want?
select 'true'
from second_table
where date_second_table > (select max(date_first_table) from first_table)
The statement: "I need to check the second query results if any date value is greater than any of the date value of first query results then it will evaluate true." This is a bit hard to follow the logic. The above returns 'true' when the values of the second query are greater than all the values of the first query.
The answer may be:
select max('true')
from second_table
where date_second_table > (select min(date_first_table) from first_table)
A key addition is the max() function, which turns this into an aggregation function so it returns one row.
EDIT:
Your question is ambiguous about what to do in the "false" case. One answer, as you suggest in the comments is:
select (case when count(*) > 0 then 1 else 0 end)
from second_table
where date_second_table > (select min(date_first_table) from first_table);
A similar approach is to use an explicit join. Although this would perform less well, it may better capture the logic:
select (case when count(*) > 0 then 1 else 0 end)
from first_table t1 join
second_table t2
on t1.date_first_table > t2.date_second_table;
SELECT DATE_SECOND_TABLE FROM SECOND_TABLE WHERE DATE_SECOND_TABLE > (SELECT DATE_FIRST_TABLE FROM FIRST_TABLE)
When you say "it will evaluate to true", you do mean it will return the result presumably

Sum all row exclude the negative numbers in Oracle Reports

I have one table with 10 rows. I want to sum the values in a particular column. But I want to exclude all the negative numbers.
How can I sum just the positive numbers and ignore the negative numbers?
This is my pictures example:
With your specifications,
Select sum(col)
from table
where col>0;
You can do something like
SELECT SUM( case when column_name > 0
then column_name
else 0
end ) sum_of_non_negative
FROM table_name
Select sum(col)
from table
where col>0
AND col not like '-%';

How do I return my records grouped by NULL and NOT NULL?

I have a table that has a processed_timestamp column -- if a record has been processed then that field contains the datetime it was processed, otherwise it is null.
I want to write a query that returns two rows:
NULL xx -- count of records with null timestamps
NOT NULL yy -- count of records with non-null timestamps
Is that possible?
Update: The table is quite large, so efficiency is important. I could just run two queries to calculate each total separately, but I want to avoid hitting the table twice if I can avoid it.
In MySQL you could do something like
SELECT
IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield,
COUNT(*)
FROM mytable
GROUP BY myfield
In T-SQL (MS SQL Server), this works:
SELECT
CASE WHEN Field IS NULL THEN 'NULL' ELSE 'NOT NULL' END FieldContent,
COUNT(*) FieldCount
FROM
TheTable
GROUP BY
CASE WHEN Field IS NULL THEN 'NULL' ELSE 'NOT NULL' END
Oracle:
group by nvl2(field, 'NOT NULL', 'NULL')
Try the following, it's vendor-neutral:
select
'null ' as type,
count(*) as quant
from tbl
where tmstmp is null
union all
select
'not null' as type,
count(*) as quant
from tbl
where tmstmp is not null
After having our local DB2 guru look at this, he concurs: none of the solutions presented to date (including this one) can avoid a full table scan (of the table if timestamp is not indexed, or of the indexotherwise). They all scan every record in the table exactly once.
All the CASE/IF/NVL2() solutions do a null-to-string conversion for each row, introducing unnecessary load on the DBMS. This solution does not have that problem.
Stewart,
Maybe consider this solution. It is (also!) vendor non-specific.
SELECT count([processed_timestamp]) AS notnullrows,
count(*) - count([processed_timestamp]) AS nullrows
FROM table
As for efficiency, this avoids 2x index seeks/table scans/whatever by including the results on one row. If you absolutely require 2 rows in the result, two passes over the set may be unavoidable because of unioning aggregates.
Hope this helps
If it's oracle then you can do:
select decode(field,NULL,'NULL','NOT NULL'), count(*)
from table
group by decode(field,NULL,'NULL','NOT NULL');
I'm sure that other DBs allow for similar trick.
Another MySQL method is to use the CASE operator, which can be generalised to more alternatives than IF():
SELECT CASE WHEN processed_timestamp IS NULL THEN 'NULL'
ELSE 'NOT NULL' END AS a,
COUNT(*) AS n
FROM logs
GROUP BY a
SQL Server (starting with 2012):
SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
FROM MyTable
GROUP BY ISDATE(processed_timestamp);
Another way in T-sql (sql-server)
select count(case when t.timestamps is null
then 1
else null end) NULLROWS,
count(case when t.timestamps is not null
then 1
else null end) NOTNULLROWS
from myTable t
If your database has an efficient COUNT(*) function for a table, you could COUNT whichever is the smaller number, and subtract.
In Oracle
SELECT COUNT(*), COUNT(TIME_STAMP_COLUMN)
FROM TABLE;
count(*) returns the count of all rows
count(column_name) returns the number of rows which are not NULL, so
SELECT COUNT(*) - COUNT(TIME_STAMP_COLUMN) NUL_COUNT,
COUNT(TIME_STAMP_COLUMN) NON_NUL_COUNT
FROM TABLE
ought to do the job.
If the column is indexed, you might end up with some sort of range scan and avoid actually reading the table.
I personally like Pax's solution, but if you absolutely require only one row returned (as I had recently), In MS SQL Server 2005/2008 you can "stack" the two queries using a CTE
with NullRows (countOf)
AS
(
SELECT count(*)
FORM table
WHERE [processed_timestamp] IS NOT NULL
)
SELECT count(*) AS nulls, countOf
FROM table, NullRows
WHERE [processed_timestamp] IS NULL
GROUP BY countOf
Hope this helps
[T-SQL]:
select [case], count(*) tally
from (
select
case when [processed_timestamp] is null then 'null'
else 'not null'
end [case]
from myTable
) a
And you can add into the case statement whatever other values you'd like to form a partition, e.g. today, yesterday, between noon and 2pm, after 6pm on a Thursday.
Select Sum(Case When processed_timestamp IS NULL
Then 1
Else 0
End) not_processed_count,
Sum(Case When processed_timestamp Is Not NULL
Then 1
Else 0
End) processed_count,
Count(1) total
From table
Edit: didn't read carefully, this one returns a single row.