Suppose to have a union, I have query a and query b
query A....
UNION
select (case when address is null then address else null end)......
the query works correctly but there is only a problem.
when case address!=null I read in the result null row:
address(column)
london square 3
new york 2
null
There is some way that when I do union null value are not returned? Anyone can help me?
One option is to use your UNION query as a subquery and return rows that aren't null.
select address
from (-- this is your current query
select address from some_table
union
select address from some_other_table
)
where address is not null
If you do:
select (case when address is null then address else null end) ...
Then:
if address is NULL then the THEN clause will be returned which is the NULL value in the address column; and
if address is not NULL then the ELSE clause will be returned which is a NULL value.
So you will ALWAYS be returning NULL.
You could simplify your query to:
SELECT NULL ...
If you want to return a non-NULL value then swap the terms in the CASE:
select case when address is null then null else address end ...
However, that can just be simplified to:
select address ...
I assume you are wanting a WHERE clause:
UNION
SELECT address
FROM table_name
WHERE address IS NOT NULL;
However, without a complete example it is difficult to determine what your exact goal is.
Related
Are there other special literal values besides NULL in SQL / PostgresQL?
NULL is nice in that we can interpret NULL as the concept of "nothing" (i.e. missing, not available, not asked, not answered, etc.), and data columns of any type can have NULL values.
I would like another value that I can interpret as representing another concept (here the idea of "everything"), in the same result set.
Is there another special value that I can return in a query, which like NULL doesn't type conflict?
Basically anything that doesn't throw ERROR: For 'UNION', types varchar and numeric are inconsistent in this toy query:
select 1 as numeral, 'one' as name UNION ALL
select 2 as numeral, 'two' as name UNION ALL
select NULL as numeral, NULL as name UNION ALL
select -999 as numeral, -999 as name UNION ALL -- type conflict
select '?' as numeral, 'x' as name -- type conflict
Here,
-999 doesn't work as its type conflicts with varchar columns
'~' doesn't work as its type conflicts with numeric columns
NULL doesn't work as it needs
More specifically here's my actual case, counting combinations of values and also include "Overall" rows in the same query. Generally I won't know or control the types of columns A, B, C in advance. And A, B, or C might also have NULL values which I would would still want to count separately.
SELECT A, COUNT(*) FROM table GROUP BY 1
UNION ALL
SELECT ?, COUNT(*) FROM table GROUP BY 1
and get a result set like:
A
COUNT
NULL
2
1
3
2
5
3
10
(all)
20
SELECT B, COUNT(*) FROM table GROUP BY 1
UNION ALL
SELECT ?, COUNT(*) FROM table GROUP BY 1
and get a result set like:
B
COUNT
NULL
2
'Circle'
3
'Line'
5
'Triangle'
10
(all)
20
You can use function CAST to convert the format to VARCHAR to be considered as string.
NOTE: Thanks to the comments above, I should completely rephrase this question as "How to COUNT/GROUP BY with ROLLUP using multiple columns of mixed/arbitrary/unknown types, and differentiate true NULL values from ROLLUP placeholders?"
The correct answer I believe is provided by #a_horse_with_no_name: use ROLLUP with GROUPING.
Below is is just me drafting that more completely with a revised example:
This toy example has an integer and a string
WITH table AS (
select 1 as numeral, 'one' as name UNION ALL
select 2 as numeral, 'two' as name UNION ALL
select 2 as numeral, 'two' as name UNION ALL
select NULL as numeral, NULL as name UNION ALL
select NULL as numeral, NULL as name UNION ALL
select NULL as numeral, NULL as name
)
select name, numeral, COUNT(*), GROUPING_ID()
FROM table
GROUP BY ROLLUP(1,2)
ORDER BY GROUPING_ID, name, numeral ;
It returns the following result:
numeral
name
count
grouping_id
note
NULL
NULL
3
0
both are true NULLs as grouping is 0
1
one
1
0
2
two
2
0
NULL
NULL
3
1
first is a true NULL, second is a ROLLUP
1
NULL
1
1
2
NULL
2
1
NULL
NULL
6
3
both NULLs are ROLLUPs
I want to filter the table without the row c
column 1
column 2
a
100
b
200
c
50
null
200
Desired output
column 1
column 2
a
100
b
200
null
200
I tried
select *
from table
where column1 <> 'c'
But since I can compare with null, I'm getting the wrong output. How do I deal with this?
You need to handle the null as follows:
select * from table where column1 <> 'c' or column1 is null
Or you can use the coalesce function as follows:
select * from table where coalesce(column1,'cc') <> 'c'
Coalesce will replace the null value in column1 with the value provided as the second argument. I have used the value which is not equal to 'c' so records with column1 as null will pass this condition
ANSI SQL, DISTINCT predicate.
select *
from table
where column1 is distinct from 'c'
However, not supported by all dbms products.
Currently I have the following sql statement:
SELECT CASE
WHEN sd.GV01 IS NULL
AND sd.GV02 IS NULL
AND sd.GV03 IS NULL
AND sd.GV04 IS NULL
AND sd.GV05 IS NULL
AND sd.CountryId = '4' THEN 4
END AS rating
FROM masterData sd
I tried to take the same way with a more short definition:
SELECT CASE
WHEN NULL IN (sd.GV01, sd.GV02, sd.GV03, sd.GV04, sd.GV05)
AND sd.CountryId = '4' THEN 4
END AS rating
FROM masterData sd
But I don't get return values, why? Can someone give me a better solution?
Your method is fine. Almost any comparison of NULL values returns NULL -- which is treated as false.
You could use COALESCE():
SELECT (CASE WHEN COALESCE(sd.GV01, sd.GV02, sd.GV03, sd.GV04, sd.GV05) IS NULL AND
sd.CountryId = '4'
THEN 4
END) AS rating
FROM masterData sd;
This is related to the results I received in this question:
Query which displays a table along with indications of which rows match another table
With some query results or a table I'm trying to identify, for each Box id, if all instances of that Box id has a 'yes' in another column, or if there is at least one 'no'. All yes's would result in yes, any no's would result in no.
eg
If this was a table:
ID, Box, Match
1,Box100, yes
2,Box100, yes
3,Box100, yes
4,Box200, yes
5,Box200, no
6,Box200, yes
7,Box300, yes
8,Box300, yes
9,Box300, yes
10,Box400, no
11,Box400, no
12,Box400, yes
What would be the query to provide these results
Box100, yes
Box200, no
Box300, yes
Box400, no
I tried to union two queries, one for the yes one for the no, using the UNIQUE statement to return only one, but that of course returns:
Box100, yes
Box200, yes
Box200, no
Box300, yes
Box400, yes
Box400, no
Which isn't what I am looking for.
I also found this to be very difficult to determine what to call this, and therefore search for solutions, hence my perhaps convoluted title. So apologies in advance.
I feel like the solution is probably pretty easy but I can't quite wrap my head around it.
Thanks
Assuming no and yes are strings, you can simply use aggregation:
select box, min(match) as match
from t
group by box;
This works because of the alphabetical ordering of the values. A more general solution is:
select box,
(case when sum(case when match = 'no' then 1 else 0 end) > 0
then 'no' else 'yes'
end) as match
from t
group by box;
Gordon's answer is what I would most likely use, however you could do it this way ....
declare #example as table (
exampleID int identity(1,1) not null primary key clustered
, box varchar(255) not null
, match varchar(25) not null
);
insert into #example (box, match)
select 'Box100', 'yes' union all
select 'Box100', 'yes' union all
select 'Box100', 'yes' union all
select 'Box200', 'yes' union all
select 'Box200', 'no' union all
select 'Box200', 'yes' union all
select 'Box300', 'yes' union all
select 'Box300', 'yes' union all
select 'Box300', 'yes' union all
select 'Box400', 'no' union all
select 'Box400', 'no' union all
select 'Box400', 'yes';
select distinct a.box
, isnull(b.match, c.match) match
from #example a
left join #example b
on a.box = b.box
and b.match = 'no'
left join #example c
on a.box = c.box
and c.match = 'yes'
Result Set:
box match
Box100 yes
Box200 no
Box300 yes
Box400 no
I have a table where the id field (not a primary key) contains either 1 or null. Over the past several years, any given part could have been entered multiple times with one, or both of these possible options.
I'm trying to write a statement that will return some value if there is ever a 1 associated with the select statement. There are lots of semi-duplicate rows, some with 1 and some with null, but if there is ever a 1, I want to return true, and if there are only null values, I want to return false. I'm not sure how to code this though.
If this is my SELECT part,id from table where part = "ABC1234" statement
part id
ABC1234 1
ABC1234 null
ABC1234 null
ABC1234 null
ABC1234 1
I want to write a statement that returns true, because 1 exists in at least one of these rows.
The closest I've come to this is by using a CASE statement, but I'm not quite there yet:
SELECT
a1.part part,
CASE WHEN a2.id is not null
THEN
'true'
ELSE
'false'
END AS id
from table.parts a1, table.ids a2 where a1.part = "ABC1234" and a1.key = a2.key;
I also tried the following case:
CASE WHEN exists
(SELECT id from table.ids where id = 1)
THEN
but I got the error subqueries are not supported in the select list
For the above SELECT statement, how do I return 1 single line that reads:
part id
ABC1234 true
You can use conditional aggregation to check if a part has atleast one row with id=1.
SELECT part,'True' id
from parts
group by part
having count(case when id = 1 then 1 end) >= 1
To return false when the id's are all nulls use
select part, case when id_true>=1 then 'True'
when id_false>=1 and id_true=0 then 'False' end id
from (
SELECT part,
count(case when id = 1 then 1 end) id_true,
count(case when id is null then 1 end) id_false,
from parts
group by part) t