Thread: [SQL] Always getting back a row, even with no results
Hi List,
I have a simple table:
CREATE TABLE my_table
(
id integer NOT NULL UNIQUE,
cat integer
);
insert into my_table (1, 2);
insert into my_table (2, 2);
insert into my_table (3, 3);
insert into my_table (4, 3);
insert into my_table (5, 2);
I want do a very basic query:
select id from my_table where cat = 3
|id|
|3|
|4|
This will of course return the two rows with that category. But I also want to be able to run the query with a non-existent cat and get a result of "null" for the id.
select id from my_table where cat = 500
would return
|id|
|NULL|
now I can do that with a union all:
select id from my_table where cat = 500
union all
select
NULL as id
|id|
|NULL|
But if I then run that query using a cat value of "3", it will not only return the results, but a third result, of NULL, which I don't want.
|id|
|3|
|4|
|NULL|
I would like to always get a result, either of NULL, or if there are actual results, or those actual results without a NULL if they exist.
I don't see it being possible with any of the coalesce/ifnull/case features, as they only action based on a single row and this can return multiple rows. Maybe something with the window functions or a CTE, but they're both new to me.
Is this possible?
Thanks
I have a simple table:
CREATE TABLE my_table
(
id integer NOT NULL UNIQUE,
cat integer
);
insert into my_table (1, 2);
insert into my_table (2, 2);
insert into my_table (3, 3);
insert into my_table (4, 3);
insert into my_table (5, 2);
I want do a very basic query:
select id from my_table where cat = 3
|id|
|3|
|4|
This will of course return the two rows with that category. But I also want to be able to run the query with a non-existent cat and get a result of "null" for the id.
select id from my_table where cat = 500
would return
|id|
|NULL|
now I can do that with a union all:
select id from my_table where cat = 500
union all
select
NULL as id
|id|
|NULL|
But if I then run that query using a cat value of "3", it will not only return the results, but a third result, of NULL, which I don't want.
|id|
|3|
|4|
|NULL|
I would like to always get a result, either of NULL, or if there are actual results, or those actual results without a NULL if they exist.
I don't see it being possible with any of the coalesce/ifnull/case features, as they only action based on a single row and this can return multiple rows. Maybe something with the window functions or a CTE, but they're both new to me.
Is this possible?
Thanks
On 11/08/2017 16:57, Jonathan Moules wrote:
Do smth like along the lines (might want to add additional code for ordering, this just happens to run correctly) :Hi List,
I have a simple table:
CREATE TABLE my_table
(
id integer NOT NULL UNIQUE,
cat integer
);
insert into my_table (1, 2);
insert into my_table (2, 2);
insert into my_table (3, 3);
insert into my_table (4, 3);
insert into my_table (5, 2);
I want do a very basic query:
select id from my_table where cat = 3
|id|
|3|
|4|
This will of course return the two rows with that category. But I also want to be able to run the query with a non-existent cat and get a result of "null" for the id.
select id from my_table where cat = 500
would return
|id|
|NULL|
now I can do that with a union all:
select id from my_table where cat = 500
union all
select
NULL as id
|id|
|NULL|
But if I then run that query using a cat value of "3", it will not only return the results, but a third result, of NULL, which I don't want.
|id|
|3|
|4|
|NULL|
I would like to always get a result, either of NULL, or if there are actual results, or those actual results without a NULL if they exist.
I don't see it being possible with any of the coalesce/ifnull/case features, as they only action based on a single row and this can return multiple rows. Maybe something with the window functions or a CTE, but they're both new to me.
select * from my_table where cat = 500 UNION select null,null LIMIT CASE WHEN (select count(*) from my_table where cat=500)>0 THEN (select count(*) from my_table where cat=500) ELSE 1 END ;
Of course you can write a function to do that for you, but what made you want this in the first place? Maybe this is bad design ?
Is this possible?
Thanks
-- Achilleas Mantzios IT DEV Lead IT DEPT Dynacom Tankers Mgmt
This will of course return the two rows with that category. But I also want to be able to run the query with a non-existent cat and get a result of "null" for the id.
untested
SELECT unnest( ARRAY( (
select id from my_table where cat = 50 ) ) );
tested, self-contained, example:
SELECT unnest(ARRAY((SELECT col FROM ( VALUES (1), (2) ) vals (col) WHERE true)))
David J.
Do smth like along the lines (might want to add additional code for ordering, this just happens to run correctly) :
select * from my_table where cat = 500 UNION select null,null LIMIT CASE WHEN (select count(*) from my_table where cat=500)>0 THEN (select count(*) from my_table where cat=500) ELSE 1 END ;
Of course you can write a function to do that for you, but what made you want this in the first place? Maybe this is bad design ?
Unfortunately this is a constraint of the environment; not good design, but SQL seems like it should be the simplest place to solve this.
I tried your example; it seems the ordering is required, otherwise the results always include the null. So the below works for anyone who finds this in the future. Thanks
select
id
from
my_table
where
cat = 2
UNION
select
null as id
ORDER BY
id ASC
LIMIT
CASE
WHEN (
select
count(*)
from
my_table
where
cat = 2
) > 0
THEN (
select count(*) from my_table where cat=2
)
ELSE
1
END;
I tried your example; it seems the ordering is required, otherwise the results always include the null. So the below works for anyone who finds this in the future. Thanks
select
id
from
my_table
where
cat = 2
UNION
select
null as id
ORDER BY
id ASC
LIMIT
CASE
WHEN (
select
count(*)
from
my_table
where
cat = 2
) > 0
THEN (
select count(*) from my_table where cat=2
)
ELSE
1
END;
Hi David,
I'm afraid I don't really understand this response (I've not done much with arrays), but it doesn't seem to work for my purpose.
No NULL is returned if there is no result (i.e. cat = 50); instead, there's simply no rows.
What aspect of Arrays is this trying to take advantage of?
Cheers,
Jonathan
---- On Fri, 11 Aug 2017 16:18:04 +0100 David G. Johnston<david.g.johnston@gmail.com> wrote ----
I'm afraid I don't really understand this response (I've not done much with arrays), but it doesn't seem to work for my purpose.
No NULL is returned if there is no result (i.e. cat = 50); instead, there's simply no rows.
What aspect of Arrays is this trying to take advantage of?
Cheers,
Jonathan
---- On Fri, 11 Aug 2017 16:18:04 +0100 David G. Johnston<david.g.johnston@gmail.com> wrote ----
This will of course return the two rows with that category. But I also want to be able to run the query with a non-existent cat and get a result of "null" for the id.untestedSELECT unnest( ARRAY( (select id from my_table where cat = 50 ) ) );tested, self-contained, example:SELECT unnest(ARRAY((SELECT col FROM ( VALUES (1), (2) ) vals (col) WHERE true)))David J.
Hi David,
I'm afraid I don't really understand this response (I've not done much with arrays), but it doesn't seem to work for my purpose.
No NULL is returned if there is no result (i.e. cat = 50); instead, there's simply no rows.
What aspect of Arrays is this trying to take advantage of?
My bad, I had tested the "false" version with a single record, without the array, and it indeed works. But the scalar subselect prevents the inner query from returning more than one row. I added the array to handle the multiple rows setup (which required testing the true path) and forgot to go back and test the false path.
The idea of the array was to keep the inner subquery scalar.
The following works on 9.5 - not positive whether it will on 10 though, we made some changes in this area.
SELECT
unnest(
COALESCE(
(SELECT array_agg(col) FROM ( VALUES (1), (2) ) vals (col) WHERE true),
ARRAY[null]::int[]
)
);
David J.
with x as
(select id,1 mark from my_table where cat = 3
union all
select null,0 mark)
select id from x where mark = (select max(mark) from x) alia;
Don't have SQL right now so can't test it.
On Fri, Aug 11, 2017 at 8:43 AM, David G. Johnston <david.g.johnston@gmail.com> wrote:
Hi David,
I'm afraid I don't really understand this response (I've not done much with arrays), but it doesn't seem to work for my purpose.
No NULL is returned if there is no result (i.e. cat = 50); instead, there's simply no rows.
What aspect of Arrays is this trying to take advantage of?My bad, I had tested the "false" version with a single record, without the array, and it indeed works. But the scalar subselect prevents the inner query from returning more than one row. I added the array to handle the multiple rows setup (which required testing the true path) and forgot to go back and test the false path.The idea of the array was to keep the inner subquery scalar.The following works on 9.5 - not positive whether it will on 10 though, we made some changes in this area.SELECTunnest(COALESCE((SELECT array_agg(col) FROM ( VALUES (1), (2) ) vals (col) WHERE true),ARRAY[null]::int[]));David J.
On 12/08/2017 05:41, Michael Moore wrote:
with x as(select id,1 mark from my_table where cat = 3union allselect null,0 mark)select id from x where mark = (select max(mark) from x) alia;Don't have SQL right now so can't test it.On Fri, Aug 11, 2017 at 8:43 AM, David G. Johnston <david.g.johnston@gmail.com> wrote:Hi David,
I'm afraid I don't really understand this response (I've not done much with arrays), but it doesn't seem to work for my purpose.
No NULL is returned if there is no result (i.e. cat = 50); instead, there's simply no rows.
What aspect of Arrays is this trying to take advantage of?My bad, I had tested the "false" version with a single record, without the array, and it indeed works. But the scalar subselect prevents the inner query from returning more than one row. I added the array to handle the multiple rows setup (which required testing the true path) and forgot to go back and test the false path.The idea of the array was to keep the inner subquery scalar.The following works on 9.5 - not positive whether it will on 10 though, we made some changes in this area.SELECTunnest(COALESCE((SELECT array_agg(col) FROM ( VALUES (1), (2) ) vals (col) WHERE true),ARRAY[null]::int[]));
I liked this!
Also an array solution, since it was mentioned, first an existing example, then a non-existing :
smadev dynacom=# select unnest(CASE WHEN arr='{}' THEN '{null}' ELSE arr END) FROM (select ARRAY(select id from flags where id=221) as arr) qry;
unnest
--------
221
(1 row)
smadev dynacom=#
smadev dynacom=# select unnest(CASE WHEN arr='{}' THEN '{null}' ELSE arr END) FROM (select ARRAY(select id from flags where id=-221) as arr) qry;
unnest
--------
(1 row)
smadev dynacom=#
David J.
-- Achilleas Mantzios IT DEV Lead IT DEPT Dynacom Tankers Mgmt
Tested
with x as
(select id,1 mark from my_table where cat = 5
union all
select null,0 mark)
select id from x where mark = (select max(mark) from x) ;
On Fri, Aug 11, 2017 at 6:57 AM, Jonathan Moules <jonathan-lists@lightpear.com> wrote:
Hi List,
I have a simple table:
CREATE TABLE my_table
(
id integer NOT NULL UNIQUE,
cat integer
);
insert into my_table (1, 2);
insert into my_table (2, 2);
insert into my_table (3, 3);
insert into my_table (4, 3);
insert into my_table (5, 2);
I want do a very basic query:
select id from my_table where cat = 3
|id|
|3|
|4|
This will of course return the two rows with that category. But I also want to be able to run the query with a non-existent cat and get a result of "null" for the id.
select id from my_table where cat = 500
would return
|id|
|NULL|
now I can do that with a union all:
select id from my_table where cat = 500
union all
select
NULL as id
|id|
|NULL|
But if I then run that query using a cat value of "3", it will not only return the results, but a third result, of NULL, which I don't want.
|id|
|3|
|4|
|NULL|
I would like to always get a result, either of NULL, or if there are actual results, or those actual results without a NULL if they exist.
I don't see it being possible with any of the coalesce/ifnull/case features, as they only action based on a single row and this can return multiple rows. Maybe something with the window functions or a CTE, but they're both new to me.
Is this possible?
Thanks