Create an empty array in an SQL query using PostgreSQL instead of an array with NULL inside
Asked Answered
L

5

15

I am using the following schema:

CREATE TABLE person (
  person_name VARCHAR PRIMARY KEY
);

CREATE TABLE pet (
  animal_name VARCHAR,
  person_name VARCHAR REFERENCES person(person_name),
  PRIMARY KEY (animal_name, person_name)
);

I wish to create a table where, for each person_name, I get an array with the pets of that person. I am using PostgreSQL 9.3.4.

I have the following values in each table:

Person

PERSON_NAME
-----------
Alice
Bob

Pet

ANIMAL_NAME | PERSON_NAME
-------------------------
Woof        | Alice
Meow        | Alice

I wish to create the following table:

PERSON_NAME | PETS
--------------------------
Alice       | {Woof, Meow}
Bob         | {}

I cannot, however, create the empty array. What I get is the following:

PERSON_NAME | PETS
--------------------------
Alice       | {Woof, Meow}
Bob         | {NULL}

This is the query I am using:

SELECT
  person.person_name,
  array_agg(pet.animal_name) AS pets
FROM
  person LEFT JOIN pet ON person.person_name = pet.person_name
GROUP BY
  person.person_name;

I understand why I am getting the array with the NULL value inside, I want to know how to get an empty array instead.

Here is a fiddle with the code needed to create the schema, insert the values and with the query I am using. The result shown in the website doesn't show the NULL value, although it is there.

EDIT

The result will be parsed to JSON, that is why {NULL} is not an acceptable result, as it will be parsed to [null], which is different from the [] I require. For the same reason, something like {""} is not an acceptable result either.

Linctus answered 29/5, 2014 at 2:29 Comment(0)
C
2

The most simple way of doing this, is to use the ARRAY constructor's sub-query variant:

SELECT
  person.person_name,
  ARRAY(SELECT animal_name FROM pet WHERE person.person_name = pet.person_name) AS pets
FROM
  person;

SQLFiddle

Caraviello answered 29/5, 2014 at 9:34 Comment(0)
G
20

I just wanna add tho this is 6 years old

array[]::varchar[]

Geodynamics answered 13/7, 2020 at 8:19 Comment(0)
W
4

Two possibilities come to mind.

One option is a UNION.

select person.person_name, array_agg(pet.animal_name) as pets
from person
join pet on person.person_name = pet.person_name
group by person.person_name

union

select person.person_name, array[]::text[] as pets
from person
left join pet on person.person_name = pet.person_name
where pet.animal_name is null

The first part uses a JOIN to get the people with pets, then the second grabs those poor people that don't have any pets at all. Separating them lets you supply a literal empty array for the pet-less people.

Another option would be to do pretty much the same thing using a LEFT JOIN to a derived table:

with pet_names as (
  select person.person_name, array_agg(pet.animal_name) as pets
  from person
  join pet on person.person_name = pet.person_name
  group by person.person_name
)
select p.person_name, coalesce(n.pets, array[]::text[])
from person p
left join pet_names n on p.person_name = n.person_name

This one is a little more natural to me as it lets you use COALESCE (the first thing you reach for you want to map NULL to something else) to supply the empty array.

Updated demo: http://sqlfiddle.com/#!15/24ccc/7

There may be other solutions, these two just seem like natural approaches to me.

Waterresistant answered 29/5, 2014 at 4:57 Comment(1)
I apologise for changing the accepted answer, but @pozs' answer seems, well, cleaner.Linctus
C
2

The most simple way of doing this, is to use the ARRAY constructor's sub-query variant:

SELECT
  person.person_name,
  ARRAY(SELECT animal_name FROM pet WHERE person.person_name = pet.person_name) AS pets
FROM
  person;

SQLFiddle

Caraviello answered 29/5, 2014 at 9:34 Comment(0)
C
1

You can use COALESCE to replace NULL values:

SELECT
  person.person_name,
  array_agg(coalesce(pet.animal_name,'')) AS pets
FROM
  person LEFT JOIN pet ON person.person_name = pet.person_name
GROUP BY
  person.person_name
;
Cosper answered 29/5, 2014 at 2:30 Comment(3)
That gives me {""} instead of {}. I believe they're not the same.Linctus
@9lo -- I don't know of any other values besides NULL and empty strings. Seems you might be talking about presentation logic instead of sql. This is the result of the above query -- sqlfiddle.com/#!15/59b18/1Cosper
Check the result in psql, via terminal. I did say that the result shown in the fiddle doesn't print the NULL value. The result gotten from the query will be parsed to JSON, where [] != [null] as well as [] != [""].Linctus
L
-1

You can create and use an empty array with these ways below. *My answer explains how to create and use an array:

SELECT ARRAY[]::VARCHAR[]; -- {}
SELECT (ARRAY[]::VARCHAR[])[1]; -- NULL
SELECT (ARRAY[]::VARCHAR[])[2]; -- NULL
SELECT (ARRAY[]::VARCHAR[])[3]; -- NULL

*Memos:

  • If you omit ::VARCHAR[], there is the error.

Or:

SELECT '{}'::VARCHAR[]; -- {}
SELECT ('{}'::VARCHAR[])[1]; -- NULL
SELECT ('{}'::VARCHAR[])[2]; -- NULL
SELECT ('{}'::VARCHAR[])[3]; -- NULL

*Memos:

  • If you omit ::VARCHAR[], the value above is not an array and the type of the value above is unknown.

Or:

SELECT string_to_array('','')::VARCHAR[]; -- {}
SELECT (string_to_array('','')::VARCHAR[])[1]; -- NULL
SELECT (string_to_array('','')::VARCHAR[])[2]; -- NULL
SELECT (string_to_array('','')::VARCHAR[])[3]; -- NULL

*Memos:

  • If you omit ::VARCHAR[], the type of the array above is TEXT[].
Laundrywoman answered 3/2, 2024 at 15:10 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.