使用PostgreSQL而不是内部为NULL的数组在SQL查询中创建一个空数组

时间:2014-05-29 02:29:10

标签: sql arrays postgresql

我使用以下架构:

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)
);

我希望创建一个表格,对于每个person_name,我会得到一个包含该人宠物的数组。我正在使用 PostgreSQL 9.3.4

我在每个表中都有以下值:

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

宠物

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

我希望创建下表:

PERSON_NAME | PETS
--------------------------
Alice       | {Woof, Meow}
Bob         | {}
但是,我无法创建空数组。我得到的是以下内容:

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

这是我正在使用的查询:

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
;

我理解为什么我在内部使用NULL值获取数组,我想知道如何获得一个空数组。

这是一个fiddle,其中包含创建架构,插入值以及我正在使用的查询所需的代码。网站上显示的结果并未显示NULL值,尽管它已存在。

修改

结果将被解析为JSON,这就是为什么{NULL}不是可接受的结果,因为它将被解析为[null],这与我要求的[]不同。出于同样的原因,{""}之类的东西也不是可接受的结果。

4 个答案:

答案 0 :(得分:2)

有两种可能性浮现在脑海中。

一个选项是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

第一部分使用JOIN来吸引有宠物的人,然后第二部分抓住那些根本没有宠物的穷人。通过分离它们,您可以为无宠物的人提供一个文字空数组。

另一种选择是使用LEFT JOIN对派生表执行几乎相同的操作:

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

这个对我来说更自然一点,因为它可以让你使用COALESCE(你想要将NULL映射到其他东西的第一件事)来提供空数组。

更新了演示:http://sqlfiddle.com/#!15/24ccc/7

可能还有其他解决方案,这两种解决方案对我来说似乎是自然而然的方法。

答案 1 :(得分:2)

最简单的方法是使用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

答案 2 :(得分:1)

您可以使用COALESCE替换NULL值:

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
;

答案 3 :(得分:0)

我只想补充一下这是6岁

array [] :: varchar []