Select distinct not-null rows SQL server 2005 - sql

I ran into the following problem.
I have a table like this:
ID ID1 ID2 ID3 ID4 ID5
1 NULL NULL NULL NULL 1
2 NULL NULL NULL 2 NULL
3 NULL NULL NULL 2 1
4 3 NULL NULL 2 NULL
5 3 NULL NULL 2 1
6 NULL 5 NULL 2 NULL
And I need to get distinct rows it terms that NULL equals any value. For this example the answer is:
ID ID1 ID2 ID3 ID4 ID5
5 3 NULL NULL 2 1
6 NULL 5 NULL 2 NULL
P.S. Here ID is primary key hence unique. ID1-ID5 - any integers.
Thanks in advance!
UPDATED
Saying that null equals any number I mean that it's absorbed by any number.

This works, don't know if it can be made any simpler
SELECT ID1, ID2, ID3, ID4, ID5
FROM IDS OUTT
WHERE NOT EXISTS (SELECT 1
FROM IDS INN
WHERE OUTT.ID != INN.ID AND
(ISNULL(OUTT.ID1, INN.ID1) = INN.ID1 OR (INN.ID1 IS NULL AND OUTT.ID1 IS NULL)) AND
(ISNULL(OUTT.ID2, INN.ID2) = INN.ID2 OR (INN.ID2 IS NULL AND OUTT.ID2 IS NULL)) AND
(ISNULL(OUTT.ID3, INN.ID3) = INN.ID3 OR (INN.ID3 IS NULL AND OUTT.ID3 IS NULL)) AND
(ISNULL(OUTT.ID4, INN.ID4) = INN.ID4 OR (INN.ID4 IS NULL AND OUTT.ID4 IS NULL)) AND
(ISNULL(OUTT.ID5, INN.ID5) = INN.ID5 OR (INN.ID5 IS NULL AND OUTT.ID5 IS NULL)))
EDIT: Found a sweeter alternative, if your ids never have negative numbers
SELECT ID1, ID2, ID3, ID4, ID5
FROM IDS OUTT
WHERE NOT EXISTS (SELECT 1
FROM IDS INN
WHERE OUTT.ID != INN.ID AND
coalesce(OUTT.ID1, INN.ID1,-1) = isnull(INN.ID1,-1) AND
coalesce(OUTT.ID2, INN.ID2,-1) = isnull(INN.ID2,-1) AND
coalesce(OUTT.ID3, INN.ID3,-1) = isnull(INN.ID3,-1) AND
coalesce(OUTT.ID4, INN.ID4,-1) = isnull(INN.ID4,-1) AND
coalesce(OUTT.ID5, INN.ID5,-1) = isnull(INN.ID5,-1))
EDIT2: There is one case where it won't work - in case two rows (with different ids) have exact same form. I am assuming that it is not there. If such a thing is present, then first create a view with a select distinct on the base table first, and then apply this query.

Statement of your problem as I understand it:
You start with the full table:
ID ID1 ID2 ID3 ID4 ID5
1 NULL NULL NULL NULL 1
2 NULL NULL NULL 2 NULL
3 NULL NULL NULL 2 1
4 3 NULL NULL 2 NULL
5 3 NULL NULL 2 1
6 NULL 5 NULL 2 NULL
Then you eliminate "duplicate" rows, ie. rows that have less, but the same values as other rows (except NULL — and the ID column is not included):
Row 1 is eliminated because row 3 is identical, but has more values in the places where row 1 has NULL.
Row 2 likewise gets eliminated by (either of) row 2 or 4.
Row 3 and 4 are eliminated by row 5.
You're then left with rows 5 and 6:
ID ID1 ID2 ID3 ID4 ID5
5 3 NULL NULL 2 1
6 NULL 5 NULL 2 NULL
My answer:
Frankly, I don't see how this could be done with SQL's SELECT DISTINCT, or more generally, with SQL's set-based logic. I could imagine that you might be able to do this kind of filtering with a more procedural approach (e.g. with cursors) — but I can't provide a solution for this.
A note about terminology:
NULL equals any value
NULL never equals any value, because NULL is itself not a value; it is the absence of a value. NULL essentially means "unknown". (The fact that NULL is not a value is the reason why you shouldn't write IDx = NULL, but IDx IS NULL instead.)

If ID1, ID2 (...) has always the same value, as in your example, you could do it
Select
SUM(id1)/COUNT(id1),
SUM(id2)/COUNT(id2),
SUM(id3)/COUNT(id3),
SUM(id4)/COUNT(id4),
SUM(id5)/COUNT(id5) From TABLE
The functions SUM and COUNT will ignore that null values.
But still little confused your question.. :)

Related

SQL Return rows with mix of nulls and non nulls in certain columns

If I have the following table
id a b c time
-----------------------------
0 1 4 "ca" 23
1 NULL NULL NULL 18
2 NULL 1 "pn" 13
3 6 NULL "ar" 27
4 1 2 NULL 24
I want to return all rows with at least one null and one non-null in columns a, b, and c. So I want to return:
id a b c time
-----------------------------
2 NULL 1 "pn" 13
3 6 NULL "ar" 27
4 1 2 NULL 24
I know I can write
select *
from table
where ((a is null and (b is not null or c is not null))
or (a is not null and (b is null or c is null)))
But what happens if I need to consider 4 columns or more? It becomes a mess. Note that the table could have 20 or more columns, of which I am only considering a small subset of columns for null/non-null analysis. Is there a concise way of doing this? Thanks
One method would be to unpivot your data, and COUNT the NULL and non-NULL values, and filter on that:
SELECT V.ID,
V.a,
V.b,
V.c,
V.time
FROM (VALUES(0,1,4,'"ca"',23),
(1,NULL,NULL,NULL,18),
(2,NULL,1,'"pn"',13),
(3,6,NULL,'"ar"',27),
(4,1,2,NULL,24))V(ID,a,b,c,time)
CROSS APPLY (SELECT COUNT(UP.V) AS NonNull,
COUNT(CASE WHEN UP.V IS NULL THEN 1 END) AS IsNull
FROM (VALUES(CONVERT(varchar(1),V.a)),
(CONVERT(varchar(1),V.b)),
(CONVERT(varchar(1),V.c)))UP(V))C
WHERE C.[IsNull] > 0
AND C.NonNull > 0;

Find values which are present in all columns in a Cable

I would like a SQL Server query which finds the Values in a cell which fills multiple columns. For example, if I have table
ID Value1 Value2 Value3
1 2 NULL NULL
1 NULL 3 NULL
1 NULL NULL 4
1 3.4 NULL NULL
2 NULL 3 NULL
2 NULL NULL NULL
3 NULL NULL 91
As in the table above, only 2 of the columns can be filled at a time(First is ID and 2nd is either of Value1, 2 or 3) and ID can be repeated multiple times.
I want to return the ID as only 1 because 1 is the only ID that populates all the three other columns. 2 fills only Value2 and all the other values of 2nd iteration of 2 are NULL where as 3 is present only in Column Value3. Is there someway that I can find the Id's which fill all the other columns.
I would love to do this preferably without a cursor but I can go for cursor if it's compulsory. Thanks
EDIT
Desired Table:
ID
1
The Statement should return only the filtered IDs which populate all the other columns.
Try this
SELECT id,
FROM TableName
GROUP BY id
HAVING MAX(value1) IS NOT NULL AND
MAX(value2) IS NOT NULL AND
MAX(value3) IS NOT NULL
Something for you try if you want some less lines of code:
select ID from dbo.Table_1 group by ID having count(Value1) > 0 AND count(Value2) > 0 AND count(Value3) > 0

Group multiple rows together

I have a table which contains the following and I am looking to group them to get the below output. Is it possible?
Input
ID Value1 Value2 Value3
5 Y NULL NULL
5 NULL 1 NULL
5 NULL NULL USA
5 NULL NULL NULL
6 N NULL NULL
6 NULL 2 NULL
6 NULL NULL GBP
6 NULL NULL NULL
Output
ID Value1 Value2 Value3
5 Y 1 USA
6 N 2 GBP
Group by the id and use max() to get the non-null value per each group
select id,
max(value1) as value1,
max(value2) as value2,
max(value3) as value3
from your_table
group by id
BTW you should think about changing you table design. It is not normalized.

Where (or even any kind of join) doesn't work with Temp table in SQLite

I have to collect data from many sources into a temp table before performing another SELECT on this table and another table. The temp table has a column called RoomID while the table (which I want to join with my temp table) also has a column called RoomID (I join these 2 tables to get more info about specified Room via its RoomID), but the returned rows are not all rows (all which I think should meet the WHERE condition).
Here is my temp table (after creating and perform a SELECT on it like this: SELECT * FROM MyTempTable):
ID1 | Name1 | ID2 | Name2 | RoomID
NULL NULL 2 A 2
2 A NULL NULL 2
1 B NULL NULL 3
3 C NULL NULL 4
4 D 5 E 8
All the values in RoomID are populated and all these RoomIDs are also present in the table I want to join with MyTempTable, here is that table (call it Room):
RoomID | Name | Note
1 Dining-room NULL
2 Bathroom NULL
3 Pantry NULL
4 Living room NULL
5 Sitting room NULL
6 Music room NULL
7 Office room NULL
8 Library NULL
With those tables above, the following query should return all the matched rows as you (and I expect):
SELECT ID1, Name1, ID2, Name2, MyTempTable.RoomID as [RoomID], Name as [Room Name], Note
FROM MyTempTable, Room
WHERE MyTempTable.RoomID=Room.RoomID
But it doesn't. I want to say more about MyTempTable, in fact it is created from 3 UNIONs, and all the values in its ZoomIDs are collected from other tables (which take part in the UNION clauses). I don't know if it matters. However the SELECT performs on the last MyTempTable shows that MyTempTable does have a column of RoomID populated with some rows. Here is what it should be after performing the SELECT above:
ID1 | Name1 | ID2 | Name2 | RoomID | Room Name | Note
NULL NULL 2 A 2 Bathroom NULL
2 A NULL NULL 2 Bathroom NULL
1 B NULL NULL 3 Pantry NULL
3 C NULL NULL 4 Living room NULL
4 D 5 E 8 Library NULL
But there isn't such a full result, the result contains only 2 rows and I even don't know why they are always those 2 rows not of any other 2 rows in the set of rows above:
ID1 | Name1 | ID2 | Name2 | RoomID | Room Name | Note
2 A NULL NULL 2 Bathroom NULL
1 B NULL NULL 3 Pantry NULL
I guess, the MyTempTable.RoomID refers to the original table in the UNION which I used to create MyTempTable, because I can see that all the returned rows seem to only belong to that table.
This is really strange, and if it's not a bug, I think the things we can do with Temp table in SQLite are so limited.
Update
You can see that, there is no row with ZoomID equal to 4 returned, but if I change the SELECT to this, it's returned - why is that?
SELECT ID1, Name1, ID2, Name2, MyTempTable.RoomID as [RoomID], Name as [Room Name], Note
FROM MyTempTable, Room
WHERE MyTempTable.RoomID=4 and Room.RoomID=4
I'm sorry to say that, all the fault belongs to me. I made a mistake in creating my tables where in this the ZoomID has type of varchar and in that it has type of int. The difference in types makes the Where Condition unable to be met. And it seems that the auto-conversion is applied only when there is at least 1 constant (like 4 above) in the comparison expression.
Sorry!

replacing values in pig latin

I have a dataset in form:
id1, id2, id3
Either of id1,id2 or id3 (or all three.. or any two) can be missing in a record.
Now if id1 is missing I want to replace it with 1
id2 by 3
id3 by 7
How do I do this.
Thanks
Use the bincond operator to test if the value is null and then replace it with the desired value. From Programming Pig, Chapter 5:
2 == 2 ? 1 : 4 --returns 1
2 == 3 ? 1 : 4 --returns 4
null == 2 ? 1 : 4 -- returns null
2 == 2 ? 1 : 'fred' -- type error, both values must be of the same type
In your example,
id2 IS NULL ? 3 : id2