在postgresql中是否有任何技巧可以使值匹配每个可能的值,一种“Catch all”值,一个反NULL?
现在,我最好的想法是选择一个“catchall”关键字并在我的查询中强制匹配。
WITH cities AS (SELECT * FROM (VALUES('USA','New York'),
('USA','San Francisco'),
('Canada','Toronto'),
('Canada','Quebec')
)x(country,city)),
zones AS (SELECT * FROM (VALUES('USA East','USA','New York'),
('USA West','USA','San Francisco'),
('Canada','Canada','catchall')
)x(zone,country,city))
SELECT z.zone, c.country, c.city
FROM cities c,zones z
WHERE c.country=z.country
AND z.city IN (c.city,'catchall');
zone | country | city
----------+---------+---------------
USA East | USA | New York
USA West | USA | San Francisco
Canada | Canada | Toronto
Canada | Canada | Quebec
如果在“城市”表中插入了新的加拿大城镇,“区域”表将自动将其识别为“加拿大”区域的一部分。 上面的查询满足了我正在寻找的功能,但如果在广泛的数据库中重复多次,它会感觉很尴尬并容易出错。
这是正确的方法吗,有更好的方法,还是我问错了问题?
非常感谢您的回答!
答案 0 :(得分:1)
就个人而言,我认为NULL
为此做出了更好的选择:
select z.zone, c.country, c.city
from cities c join
zones z
on c.country = z.country and
(c.city = z.city or z.city is null);
甚至:
select z.zone, c.country, c.city
from cities c join
zones z
on c.country = z.country and
c.city = coalesce(z.city, c.city);
根据Denis的说法,Postgres似乎足够聪明,可以在country
和city
的第一个查询中使用索引。
您也可以进行两部分联接,如果您在zone(country)
和zone(country, city)
都有索引,则可以进行两部分联接:
select coalesce(zcc.zone, zc.zone) as zone, c.country, c.city
from cities c join
zones zcc
on c.country = z.country and
c.city = z.city join
zones zc
on c.country = z.country and
zc.city is null;
虽然有点复杂,但两个连接都应该能够使用适当的索引。
答案 1 :(得分:0)
我怀疑有类似的东西。一种简单的方法,但不是非常优雅,高效或灵活,是定义你的函数cities_equals(text t1, text t2)
,如果两者都不为空,则返回true,并且(t1 == t2或t1 ==' catchall' OR t2 ==' catchall')
答案 2 :(得分:0)
将您的条件更改为SIMILAR TO并构造一个匹配两者的正则表达式:
and z.city similar to '(' || c.city || ')|(%)'