假设我在Postgres中有一张看起来像这样的表 - 注意拉链字段是json。
cities
name (text) | zips (json)
San Francisco | [94100, 94101, ...]
Washington DC | [20000, 20001, ...]
现在我想做select * from cities where zip=94101
之类的事情,换句话说,就是测试会员资格。
我尝试使用WHERE zips ? '94101'
并获得operator does not exist: json ? unknown
。
我尝试使用WHERE zips->'94101'
,但不确定要放在那里,因为Postgres抱怨argument of WHERE must by type boolean, not type json
。
我想要什么?我如何解决9.3和9.4?
编辑是的,我知道我应该使用本机数组类型...我们使用的数据库适配器不支持此功能。
答案 0 :(得分:4)
在PostgreSQL 9.4+中,您可以将@>
运算符与jsonb
类型一起使用:
create table test (city text, zips jsonb);
insert into test values ('A', '[1, 2, 3]'), ('B', '[4, 5, 6]');
select * from test where zips @> '[1]';
这种方法的另一个优点是9.4的新GIN indexes加速了对大桌面的查询。
答案 1 :(得分:2)
对于PostgreSQL 9.4+,您应该使用json[b]_array_elements_text()
:
(包含运算符?
执行类似的操作,但对于JSON数组,它只能找到完全匹配,如果您的数组包含字符串而不是数字,则只能发生匹配)
create table cities (
city text,
zips jsonb
);
insert into cities (city, zips) values
('Test1', '[123, 234]'),
('Test2', '[234, 345]'),
('Test3', '[345, 456]'),
('Test4', '[456, 123]'),
('Test5', '["123", "note the quotes!"]'),
('Test6', '"123"'), -- this is a string in json(b)
('Test7', '{"123": "this is an object, not an array!"}');
-- select * from cities where zips ? '123';
-- would yield 'Test5', 'Test6' & 'Test7', but none of you want
-- this is a safe solution:
select cities.*
from cities
join jsonb_array_elements_text(
case jsonb_typeof(zips)
when 'array' then zips
else '[]'
end
) zip on zip = '123';
-- but you can use this simplified query, if you are sure,
-- your "zips" column only contains JSON arrays:
select cities.*
from cities
join jsonb_array_elements_text(zips) zip on zip = '123';
对于9.3,您可以使用json_array_elements()
(并手动将拉链转换为text
):
select cities.*
from cities
join json_array_elements(zips) zip on zip::text = '123';
注意:对于9.3,您无法使查询安全(至少很容易),您只需要在zips
列中存储JSON数组。此外,上面的查询将找不到任何字符串匹配,您的数组元素需要是数字。
注释2 :对于9.4+,您也可以使用json
的安全解决方案(不仅仅是jsonb
,但您必须拨打json_typeof(zips)
而不是jsonb_typeof(zips)
)。
编辑:实际上,@>
运算符在PostgreSQL 9.4+中更好,为@Ainar-G mentioned(因为它是可索引的)。一点注意事项:如果你的列和查询都使用JSON数字(或JSON字符串,但没有混合),它只会找到行。
答案 2 :(得分:1)
对于9.3,您可以使用json_array_elements()
。我现在无法在版本9.4中使用jsonb进行测试。
create table test (
city varchar(35) primary key,
zips json not null
);
insert into test values
('San Francisco', '[94101, 94102]');
select *
from (
select *, json_array_elements(zips)::text as zip from test
) x
where zip = '94101';