SQL selecting values with Null and 0 values from range null, 0 & 1 - sql

One of the columns returned by a T-SQL query has one of these three values
NULL, 0, 1
I am trying to filter out the 1 values, but when I use these clause:
Query:
select foo
from dbo.table1
where ..
Clause:
where foo <> 1: returns only the data with 0 values in the column
Where foo is null: returns only the null values in the column
where foo in (Null, 0): returns only the data with 0 values in the column
What is the correct method to filter out the data?

Since there are only 3 values, this is enough:
where isnull(foo, 0) <> 1
or:
where isnull(foo, 0) = 0

In SQL Server, you can do:
where foo <> 1 or foo is null
Or, if you know that there really are only three values, something like:
where coalesce(foo, -1) <> 1
SQL Server does not have a NULL-safe comparison. Standard SQL supports:
where foo is distinct from 1
but that is not available in SQL Server.

Related

SQL check if column value is true

I have four columns A,B,C,D and are all of type bit.
Is there a way in SQL to check if all four column values are 1
and not 0 for a single record?
You can use bit-wise operators e.g.:
select 1 & 0 & 1 & 0
yields 0, which you can easily test
Assuming that you want to treat the Null values as 0(false). Use following query
Select A,B,C,D
from #mytable t
where t.A = 1
and t.B = 1
and t.C = 1
and t.D = 1

SQL statement - use avg and count together but in different conditions

Assume we have the table as follows,
id Col-1 Col-2
A 1 some text
B 0 some other text
C 3
...
Take the table above as example, I want to build one SQL statement which would output the result: 2, 2.
The first value is the avg of all col-1 values except for 0, that is (1+3)/2 = 2. (If 0 is counted, then the result would be (1+0+3)/3 = 1, which is not what I want.)
The second value is the total number of all col-2 that is not empty. So the value is 2.
P.S, I know how to create them separately. What I prefer is to create only 1 statement to get both results.
For the first you can use NULLIF as null values are ignored in aggregations such as AVG.
For the second I assume you want to only count values not NULL or empty string.
SELECT AVG(NULLIF(Col1, 0)),
COUNT(CASE WHEN Col2 <> '' THEN 1 END)
FROM T
You want conditional aggregation:
select avg(case when col1 <> 0 then col1 end) as avg_not_zero,
count(col2) as num_not_empty
from table t;
As a note: 0 does not mean that the value is empty. Often NULL is used for this purpose in SQL, although strictly speaking, NULL means an unknown value.
Note: If "empty" could mean the empty string instead of NULL:
select avg(case when col1 <> 0 then col1 end) as avg_not_zero,
count(nullif(col2, '')) as num_not_empty
from table t;

Hiding a row in a table with a query when 3 columns have null values

I am looking for the best way to build a query which would hide the record (row) in the event that three field values (in three different columns) would be null. The code below is giving me a syntax run time error message of 3075. Also, I am not sure if it is causing a problem but the code below is executed from a main form and impacting the subform frmStaticDataSkills02.
sql_get = "SELECT [tblCompetency02].[HighLevelObjective], [tblCompetency04].[Self], [tblCompetency04].[SelfSpecialLanguage], [tblCompetency04].[SelfChecklist], [tblCompetency04].[Team], [tblCompetency04].[TeamSpecialLanguage], [tblCompetency04].[TeamChecklist], [tblCompetency04].[Organisation], [tblCompetency04].[OrganisationSpecialLanguage], [tblCompetency04].[OrganisationChecklist], [tblCompetency02].[Competency] FROM [tblCompetency04] INNER JOIN [tblCompetency02] ON [tblCompetency04].[HighLevelObjective] = [tblCompetency02].[ID] WHERE ([tblcompetency04].[self]<>"" or [tblcompetency04].[team]<>"" or [tblcompetency04].[organisation]<>"")"
Form_frmStaticDataSkills02.Form.RecordSource = sql_get
In a general sense, in a table of N columns, you can explicitly count the number of NULL columns in a table and then add them up and compare the count of nulls to 3 in a where predicate:
SELECT *
FROM MyTable x
WHERE
((IIF(x.COL1 IS NULL, 1 , 0) +
IIF(x.COL2 IS NULL, 1 , 0) +
IIF(x.COL3 IS NULL, 1 , 0) +
IIF(x.COL4 IS NULL, 1 , 0))) <> 3;
(Obviously, keep adding IIF statements for all N columns of the table
This will return the data if not all three columns are NULL:
where not (col1 is null and col2 is null and col3 is null)
This is the same after applying algebra of logic: return the row if any of the three rows is NOT NULL
where col1 is not null or col2 is not null or col3 is not null)
End your query with:
WHERE [column_1] IS NOT NULL AND [column_2] IS NOT NULL AND [column_3] IS NOT NULL
You can do that in your where clause by specifying that all 3 fields should not be NULL, the result set that is returned will not have records where all 3 fields are NULL.
SELECT *
FROM tablename
WHERE
field1 IS NOT NULL AND
field2 IS NOT NULL AND
field3 IS NOT NULL
If you do not want to have rows returned where any one of the columns has null values you would use OR. For example:
SELECT *
FROM tablename
WHERE
field1 IS NOT NULL OR
field2 IS NOT NULL OR
field3 IS NOT NULL

What SQL query can answer "Do these rows exist?"

Here is the code to create the database:
CREATE TABLE foo (
id TEXT PRIMARY KEY,
value TEXT
);
INSERT INTO foo VALUES(1, 10), (2, 20), (3, 30), (5, 50);
Now I have a set of rows and I want back 0 if the row doesnt exist, 1 if the row exists but is not the same, and 2 if the row exists exactly.
So the result of the query on (1, 11), (2, 20), (4, 40) should be 1, 2, 0.
The reason I want this is to know what query to use to insert the data into the database. If it is a 0, I do a normal insert, if it is a 1 I do an update, and if it is a 2 I skip the row. I know that INSERT OR REPLACE will result in nearly the same rows, but the problem is that it doesnt trigger the correct triggers (it will always trigger an on insert trigger instead of an update trigger or no trigger if the row exists exactly).
Also, I want to do one query with all of the rows, not one query per row.
The idea is to use an aggregation query. Count the number of times that the id matches. If there are none, then return 0. Then check the value to distinguish between 1 and 2:
select (case when max(id = 1) = 0 then 0
when max(id = 1 and value = 11) = 0 then 1
else 2
end) as flag
from table t;
You need to plug the values into the query.
EDIT:
If you want to match a bunch of rows, do something like this:
select testvalue.id,
(case when max(t.id = testvalue.id) = 0 then 0
when max(t.id = testvalue.id and t.value = testvalue.value) = 0 then 1
else 2
end) as flag
from table t cross join
(select 1 as id 10 as value union all
select 2, 20 union all
select 4, 40
) as testvalues
group by testvalues.id;
You can use the EXISTS argument in Transact-SQL. MSDN Documentation.
This returns true if a row exists. You can then use an If statement within that to check if the row is the same or different, and if true, use the RETURN argument with your specified values. MSDN Documentation.
This is based off of Gordon Linoff's answer so upvote him. I just wanted to share what I actually went with:
select testvalues.id,
(case when t.id != testvalues.id then 0
when t.value != testvalues.value then 1
else 2
end) as flag
from (select 1 as id, 11 as entity union all
select 2, 20 union all
select 4, 40
) as testvalues
LEFT OUTER JOIN foo t on testvalues.id=t.id
This prevents the full memory usage of a cross join and group by clauses.

<> operator in SQL

I have a table like this
ID Name IsDeleted
1 Yogesh Null
2 Goldy 1
Now when I run this query
select *
from tableName
where IsDeleted <> 1
I should get ID 1 record, But I am not getting it,
But when I run this
select *
from tableName
where IsDeleted is null
I get ID 1 record,
Why am I facing this behavior ??
Isn't NULL <> 1 is a true statement in SQL ??
IsDeleted is a bit type field with Allow Null true
select * from table
where COALESCE(IsDeleted, 0) <> 1
-- or ISNULL instead of COALESCE.
--ISNULL seems to be better in subqueries, but it's not ANSI SQL.
or
select * from table
where IsDeleted <> 1 or IsDeleted IS NULL
Comparing something with null will always result in unknown. That is why you need to use the is operator to compare null or use functions like COALESCE or isnull to replace null
select *
from tableName
where isnull(IsDeleted,0) <> 1
you compare different types. in this case its an other type (unknown) and not comparable
use the or statement to compare each type seperate
WHERE IsDeleted <> 1 OR IsDeleted is null
Learn about NULL - a comparison with NULL (in standard SQL) yields UNKNOWN, which is not true nor false (and the reason why your expectation is not met).
Try this:
PRINT CASE
WHEN 1 = NULL THEN '1 = NULL'
WHEN 1 <> NULL THEN '1 <> NULL'
ELSE '1 is neither = NULL nor <> NULL'
END
You can either first make sure that you don't have a NULL value (for instance by using the ISNULL or COALESCE functions), or use a condition with the operator IS NULL or IS NOT NULL.
Normal practice would dictate that if you had a column that essentially was a true false, yes no type of field then you should use a bit field with the default value set to 0.
So in your case above you could just run this:
select *
from tableName
where IsDeleted = 0
But in answer to your above question, if the Null is a true NULL value in the table then this will work for you:
select *
from tableName
where IsDeleted is null
or
select *
from tableName
where isnull(IsDeleted,0) = 0
to get record 1 and
select *
from tableName
where IsDeleted is not null
to get record 2
Good luck
Paul.