匹配每个可能值的值(当然除了null)?

时间:2013-06-05 20:56:00

标签: sql postgresql

在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

如果在“城市”表中插入了新的加拿大城镇,“区域”表将自动将其识别为“加拿大”区域的一部分。 上面的查询满足了我正在寻找的功能,但如果在广泛的数据库中重复多次,它会感觉很尴尬并容易出错。

这是正确的方法吗,有更好的方法,还是我问错了问题?

非常感谢您的回答!

3 个答案:

答案 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似乎足够聪明,可以在countrycity的第一个查询中使用索引。

您也可以进行两部分联接,如果您在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 || ')|(%)'