Change aggregate functions to output NULL when a element is NULL - sql

Every question I search for about the warning
Warning: Null value is eliminated by an aggregate or other SET operation.
Typically people want to treat the NULL values as 0. I want the opposite, how do I modify the following stored procedure to make it return NULL instead of 1?
CREATE PROCEDURE TestProcedure
AS
BEGIN
select cast(null as int) as foo into #tmp
insert into #tmp values (1)
select sum(foo) from #tmp
END
GO
I thought it would be SET ANSI_NULLS ON (I tried before the declaration, within the procedure itself, and before executing the procedure in my test query) but that did not appear to change the behavior of SUM(.

The sum() function automatically ignores NULL. To do what you want, you need an explicit checK:
select (case when count(foo) = count(*) then sum(foo) end)
from #tmp;
If you want to be explicit, you could add else NULL to the case statement.
The logic behind this is that count(foo) counts the number of non-NULL values in foo. If this is equal to all the rows, then all the values are non-NULL. You could use the more verbose:
select (case when sum(case when foo is null then 1 else 0 end) > 0
then sum(foo)
end)
And, I want to point out that the title is quite misleading. 1 + NULL = NULL. The issue is with the aggregation functions, not the arithmetic operators.

Looking for a null value with EXISTS may be the fastest:
SELECT
CASE WHEN EXISTS(SELECT NULL FROM tmp WHERE foo IS NULL)
THEN NULL
ELSE (SELECT sum(foo) from tmp)
END

Just say
select case sign(sum(case when foo is null then 1 else 0 end))
when 1 then null
else sum(foo)
end
from some_table
...
group by
...
That's about all you need.

Related

Case Statement Sql Multiple column check for dates

I have a stored procdure that uses case statement as follows: What I am trying to do is evaluate 2 columns in the testTable for dates. So the below case statement says that if stop_date is null or greater than current date then set is_active cloumn is Y else N
What I am trying to do is also evaluate another date column say another_stop_date and check if it is null or has a date greater then today and use same logic to update the is_active column
I am not sure if we can use multiple case statement logic to update a single column?
I have commented the code below where I am not getting the right results
Basically need to evaluate stop_dt and another_stop_date columns from testTable!
USE [Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[p_test]
#Blank_Row CHAR(1) = 'N'
AS
BEGIN
SET NOCOUNT ON
DECLARE #TD DATETIME
SELECT #TD = GETDATE()
DECLARE #tempTable TABLE (
ID INT,
c_id INT,
desc varchar(40),
date datetime,
s_col TinyINT,
is_active char(1),
stuff VARCHAR(8))
INSERT INTO #tempTable
SELECT id, c_id, desc, max( date ), 1,
CASE WHEN (stop_dt IS NULL OR stop_dt > #TD) THEN 'Y'
--//Case When (another_stop_date is NULL or another Stop_date > #TD) THEN 'Y'<-----confused here
ELSE 'N' END,
stuff
FROM testTable
GROUP BY id, stop_dt, c_id, desc, stuff, another_stop_date
Select * from tempTable
You can combine clauses in a case statement with the usual logical operators, as well as having separate cases:
Case
When
(stop_dt is null or stop_dt > #td) and
(another_stop_date is null or another_stop_date > #td)
Then 'Y'
Else 'N'
End
Case statement operate close to if statements and can have multiple clauses.
Case when condition_1 > 1 then 'hi'
when condition_1 < 14 then 'no'
when condition_89 > 12 then 'why is this here'
else 1
end
Apply it to your statement:
CASE WHEN (stop_dt IS NULL OR stop_dt > #TD) THEN 'Y'
When (another_stop_date is NULL or another Stop_date > #TD) THEN 'Y'<-----confused here
ELSE 'N' END

Using Case Statement in SQL with parameter/variable to check for Null values

I am trying to write a SQL Select statement to return records based on a user input through a front end.
I want to write the Select statement like this:
SELECT somefields
FROM sometable
WHERE CASE variable
WHEN 'blank' THEN field IS NULL
ELSE field = field
END
Basically I either want to filter a column to find NULL values or ignore the filter and return all values depending on the value of the variable. I know that the results of the CASE statement is not executable but how can I do this?
When variable is 'blank', the following query will give you rows where field is NULL. When variable is anything else, it will give you all rows:
SELECT somefields
FROM sometable
WHERE
(variable = 'blank' AND field IS NULL)
OR (variable <> 'blank')
You can use NULLIF() (link is for SQL Server, but NULLIF() should be standard):
SELECT somefields
FROM sometable
WHERE field = NULLIF(variable, 'blank')
The following snippet should behave as follows:
when #variable is null, return all rows
when #variable = 'blank', return all rows where field is null or field = 'blank'
otherwise, return rows where #variable equals field
Code snippet:
WHERE 1 = CASE
WHEN #variable is null then 1
WHEN #variable = 'blank' and field is null then 1
WHEN #variable = field then 1
END
SELECT somefields
FROM sometable
WHERE ((variable IS NULL OR variable = 0) OR (variable = field))
WHERE Criteria is apply when variable have value
For Example:
DECLARE #CityName VARCHAR(50)
SET #CityName = NULL
SELECT CityName
FROM City
WHERE ((#CityName IS NULL ) OR (#CityName = CityName ))
When City is null then tables return all rows
I think I get what you're after. Something like this maybe?
SELECT field1,
field2,
CASE variable
WHEN 'blank' THEN NULL
ELSE field3
END as field3
FROM sometable
Think I understand what you mean....for example....
SELECT
House, Postcode
from
SomeTable
where
(House=isnull(#House,House) or (House is null and #House is null))
and
(Postcode=isnull(#Postcode,Postcode) or (Postcode is null and #Postcode is null))
First bit of the conditional where is to use the variable, when present (the isnull bit is to ignore the variable if it's null)
Second bit of the conditional where is in case your evaluative field is null also as effectively fields don't = null they are 'is null'.
Confused? Good. Works on what I'm doing though!
Here is my solution based on #Andomar answer above aimed at anyone testing an input varchar value, you need to test the parameter in the right order as per the example below:
FIELD1 = CASE
WHEN #inputParameter = '' THEN FIELD1
WHEN #inputParameter <> FIELD1 THEN NULL -- if input is some text but does not match
WHEN #inputParameter IS NULL THEN FIELD1
WHEN #inputParameter != '' AND FIELD1 = #inputParameter THEN FIELD1
END
Hope this helps someone.

How to create a ternary condition on a bit field in T-SQL

I have a SQLExpress table that includes a bit field for storing TRUE/FALSE state.
Something like:
+----+---------+
| ID | IsAlive |
+----+---------+
| 1 | 1 |
| 2 | 0 |
| 3 | NULL |
| 4 | 1 |
+----+---------+
Using that table as our example, I want to create one Stored Procedure that will do any one of the following:
Retrieve all records.
Retrieve only the records with IsAlive=1.
Retrieve only the records with IsAlive=0 or NULL.
I am trying to think of how I can create my query without having to write IF/ELSE conditions - It seems to me there is a better/cleaner way than to do something like this:
-- The ternary logic...
-- 0 or NULL retrieves records where IsAlive = 0 or NULL
-- 1 retrieves records where IsAlive = 1
-- Otherwise return all records
-- sproc .....
#IsAlive tinyint = 2 -- Return all records by default
AS
BEGIN
IF(#SentToNTService = 0 OR #SentToNTService = 1)
BEGIN
SELECT *
FROM MyTable
WHERE IsAlive = #IsAlive;
END
ELSE -- Lame redundancy
BEGIN
SELECT *
FROM MyTable
END
END
Is there another way of creating the same results without having to create two different queries as I did above?
2 suggestions of how to do this:
Assuming your variable #isalive is declared as 'bit' as well (which is should be)
SELECT * FROM #t
WHERE #isalive is null or #isalive = coalesce(isalive, 0)
If you want to use a 'bit compare' solution that doesn't require #isalive to be 'bit' (it will work for bit as well as tinyint)
SELECT * FROM #t
WHERE coalesce((1-coalesce(isalive, 0)) ^ #isalive, 1) > 0
Second solution is for nerds like me. Some hardcore people may find it interesting (or at least amusing) as I think it offer the best possible performance (please, someone correct me if i am wrong). It is a powerful solution but hard to read.
This will do what you want:
SELECT *
FROM MyTable
WHERE COALESCE(IsAlive, 0) = COALESCE(#IsAlive, COALESCE(IsAlive, 0))
Based on the value of #IsAlive:
If NULL, then will return everything (because the condition is always true)
If 1, then will return those rows with IsAlive = 1
If 0, then will return those rows with IsAlive = 0 or NULL
COALESCE is a function that returns it's first argument, unless it's NULL, in which case it returns its second argument.
So the LHS returns 0 if IsAlive is NULL or 0 and 1 if IsAlive is 1.
The RHS returns the same when the stored procedure argument #IsAlive is NULL and just returns the #IsAlive argument otherwise.
EDIT:
This assumed that #IsAlive is BIT. In the case of tinyint you can add a case statement:
SELECT *
FROM MyTable
WHERE COALESCE(IsAlive, 0) = CASE #IsAlive
WHEN 0 THEN 0
WHEN 1 THEN 1
ELSE COALESCE(IsAlive, 0)
END
try this:
SELECT * FROM MyTable WHERE ISNULL (IsAlive, 0) = ISNULL (#IsAlive, 0)
UNION
SELECT * FROM MyTable WHERE ISNULL (#IsAlive, 0) > 1
This isnt exact, but pretty close to what you can do:
SELECT *
FROM MyTable
WHERE CASE #IsAlive
WHEN 0 THEN IsAlive = #IsAlive
WHEN 1 THEN IsAlive = #IsAlive
ELSE 1=1 --dummy true value, when null or anything else
END
Something like this should also work.
SELECT *
FROM MyTable
WHERE (#IsAlive = 0 and IsAlive=0)
OR (#IsAlive =1 and IsAlive =1)
OR (#IsAlive is null)

Select the result of a comparison in SQL statement

How would I achieve the following:
select (1 < 2) as One, (1 > 2) as Two
so that it would yield the following results:
One Two
-----------------
True False
I'm using SQL Server but a cross DBMS example would be good.
Assuming this is SQL server, you can use CASE statement.
select (case when (1 < 2) then 'True' else 'False' end) as one,
(case when (1 > 2) then 'True' else 'False' end) as two
from table
In the place of condition, you can use any variable or any column values too. Basically an expression.
Well, in Oracle you could do something like
SELECT CASE
WHEN 1 < 2 THEN
'TRUE'
ELSE
'FALSE'
END AS ONE,
CASE
WHEN 1 > 2 THEN
'TRUE'
ELSE
'FALSE'
END AS TWO
FROM DUAL;
Note that Oracle doesn't have a BOOLEAN type in the database (as opposed to PL/SQL, which does have BOOLEAN's) so the case expressions return character strings.
Share and enjoy.
Use a case statement:
declare #value1 int, #value2 int
set #value1 = 1
set #value2 = 2
select
case when (#value1 < #value2) then 'True' else 'False' end as One
case when (#value1 > #value2) then 'False' else 'True' end as Two
from table
Depending on your need, you can hard code in the values, or you can do something similar to this for when you may want to change the values. You could also combine the case statement into one column, or break it out for doing less than or equal type comparisons as well.

SQL Server variables

Why do these queries return different values? The first returns a result set as expected, but the second (which as far as I can tell is exactly the same) does not. Any thoughts?
1:
declare #c varchar(200)
set #c = 'columnName'
select top 1 *
from myTable
where #c is not null
and len(convert(varchar, #c)) > 0
2:
SELECT top 1 *
FROM myTable
WHERE columnName IS NOT NULL
and len(convert(varchar,columnName)) > 0
It's because they aren't the same query -- your variable text does not get inlined into the query.
In query 1 you are validating that #c is not null (true, you set it) and that its length is greater than 0 (true, it's 10). Since both are true, query 1 becomes:
select top 1 * from myTable
(It will return the first row in myTable based on an appropriate index.)
EDIT: Addressing the comments on the question.
declare #myTable table
(
columnName varchar(50)
)
insert into #myTable values ('8')
declare #c nvarchar(50)
set #c = 'columnName'
select top 1 *
from #myTable
where #c is not null
and len(convert(varchar, #c)) > 0
select top 1 *
from #myTable
where columnName is not null
and len(convert(varchar,columnName)) > 0
Now when I run this both queries return the same result. You'll have to tell me where I'm misrepresenting your actual data / query to get more help (or just expand upon this to find a solution).
In the first query, you are checking the value 'columnName' against the parameters IS NOT NULL and length > 0. In the second query, you are checking the values in the columnName column against those parameters.
It should be noted that query 1 will always return one row (assuming a row exists), where query 2 will only return a row if the contents of columnName are not null and length > 0.
The first query actually evaluates as
select top 1 * from myTable where 'columnName' is not null and len(convert(varchar, 'columnName' )) > 0
Not as what you were hoping for.expected.
The two querys are not the same as in the second query you are evaluating the actual value of the field columnname. The following is the equivalent of your first function.
SELECT top 1 * FROM myTable WHERE 'columnName' IS NOT NULL and len(convert(varchar,'columnName')) > 0
They're not the same - the first is checking the variable while the second is checking the column. "where #c is not null" means where the variable #c isn't null - which it isn't, since it contains the value 'columnName'. "where columnName is not null" means where the field columnName doesn't contain a null. And the same for the evaluation of the length.