【问题标题】:Matching patterns between multiple columns多列之间的匹配模式
【发布时间】:2012-07-01 10:03:18
【问题描述】:

我有两列,分别是 MainSub。 (它们可以是同一张桌子,也可以不同)。

Main 是长度为 20 的 varchar,Sub 是长度为 8 的 varchar。
SubMain始终子集,它是 @987654327 的最后 8 个字符@。

我可以使用substr("Main",13,8) 成功设计一个匹配模式的查询

查询:

select * from "MainTable"
 where substr("MainColumn",13,8) LIKE (
   select "SubColumn" From "SubTable" Where "SubId"=1043);

但我想在查询中使用 Like、%、_ 等,以便我可以松散地匹配模式(不是全部 8 个字符)。

问题是我该怎么做。?!

我知道下面的查询是完全错误,但我想实现这样的目标,

Select * from "MainTable"
 Where "MainColumn" Like '%' Select "SubColumn" From "SubTable" Where "SubId"=2'

【问题讨论】:

    标签: postgresql pattern-matching


    【解决方案1】:

    到目前为止的答案未能解决您的问题:

    但我想在查询中使用 Like、%、_ 等,以便我可以松散匹配 模式(不是全部 8 个字符)。

    使用LIKE= 几乎没有什么区别,只要匹配整个字符串(并且字符串中没有通配符)。为了使搜索模糊,您需要替换部分模式,而不仅仅是添加。

    例如,匹配subcolumn 的最后 7 个(而不是 8 个)字符:

    SELECT *
    FROM   maintable m
    WHERE  left(maincolumn, 8) LIKE 
           ( '%' || left((SELECT subcolumn FROM subtable WHERE subid = 2), 7));
    

    我使用更简单的left()(在 Postgres 9.1 中引入)。
    could 简化为:

    SELECT *
    FROM   maintable m
    WHERE  left(maincolumn, 7) =
           (SELECT left(subcolumn,7) FROM subtable WHERE subid = 2);
    

    但如果你使用我在后面提到的特殊索引,你不会,因为函数索引中的表达式必须精确匹配才能使用。

    您可能对扩展名pg_tgrm 感兴趣。

    在 PostgreSQL 9.1 中,每个数据库运行一次:

    CREATE EXTENSION pg_tgrm;
    

    两个原因:

    • 它提供similarity operator %。有了它,您可以构建智能相似度搜索:

      --SELECT show_limit();
      SELECT set_limit(0.5); -- adjust similarity limit for % operator
      
      SELECT *
      FROM maintable m
      WHERE left(maincolumn, 8) %
            (SELECT subcolumn FROM subtable WHERE subid = 2);
      
    • 它为LIKE% 提供index support

      如果读取性能比写入性能更重要,我建议您创建一个functional GIN 或 GiST 索引,如下所示:

      CREATE INDEX maintable_maincol_tgrm_idx ON maintable
      USING gist (left(maincolumn, 8) gist_trgm_ops);
      

      此索引支持任一查询。请注意,写入操作会产生一些成本。
      A quick benchmark for a similar case in this related answer

    【讨论】:

    • 如果您使用 GiST 索引而不是 GIN,按相似性排序的相似性搜索 DESCLIMIT 将使用索引的 KNN 搜索——索引实际上将按顺序返回行的“最佳匹配”。这可能比替代方案快得多。 set_limit() 中使用的值可能会对 KNN 搜索的性能产生重大影响,因此请使用它以确保您没有包含太“松散”而无法真正引起兴趣的匹配项。 (KNN 是一种表示法,表示您想要“k”个最近的邻居,其中“k”是您提供的数字。)
    • @indyaah:我添加了一个指向相关答案的链接,该链接说明了 GiST 和 GIN 索引的性能——就像 Kevin 描述的那样。还修改了此处的示例以显示 GiST 索引,这是更好的选择。
    【解决方案2】:

    试试

    SELECT t1.* from "Main Table" AS t1, "SubTable" AS t2
     WHERE t2.SubId=1043
       AND substr(t1.MainColumn, 13, 8) LIKE "%" || CAST(t2.SubColumn as text);
    

    【讨论】:

    • 其实我想避免使用 substr()。
    【解决方案3】:

    LIKE 的参数是一个普通的字符串,所以这里所有的字符串操作都是有效的。 在您的情况下,您需要将通配符与目标子字符串连接起来,就像@bksi 建议的那样:

    ... LIKE '%'||CAST("SubColumn" AS test) ...
    

    但请注意,此类模式(以% 通配符开头的模式)性能不佳。看看PostgreSQL LIKE query performance variations

    我会推荐:

    • 坚持当前的substr("MainColumn", 13, 8) 方法;
    • 避免使用LIKE 并改用相等比较 (=)(尽管如果LIKE 模式不包含通配符,则它们相等,但更容易阅读查询);
    • 通过以下方式在“MainTable”上构建expression index

      CREATE INDEX i_maincolumn ON "MainTable" (substr("MainColumn", 13, 8));
      

    在我看来,这种组合会表现得更好。

    并为表/列使用小写名称,这样您就可以避免双引号。

    【讨论】:

    • 谢谢!真的很感激:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-02
    • 1970-01-01
    • 2015-08-10
    • 1970-01-01
    • 2019-02-25
    • 2016-01-02
    • 2016-04-24
    相关资源
    最近更新 更多