Postgresql: сопоставление шаблонов между двумя столбцами

У меня есть две колонки: Main и Sub. (они могут быть одинаковой таблицы или нет).

Main является varchar длиной 20 и Sub является varchar длины 8.
Sub - это всегда подмножество Main, и это последние 8 символов Main.

Я мог бы успешно спроектировать запрос для соответствия шаблону с помощью substr("Main",13,8)

Query:

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

но я хочу использовать Like,%, _ etc в моем запросе, чтобы я мог свободно сопоставлять шаблон (это не все 8 символов).

Вопрос в том, как я могу это сделать.?!

Я знаю, что запрос ниже ПОЛНОСТЬЮ НЕПРАВИЛЬНО, но я хочу достичь чего-то подобного,

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

Ответ 1

Ответы до сих пор не могут решить ваш вопрос:

но я хочу использовать Like,%, _ etc в моем запросе, чтобы я мог свободно совпадать шаблон (это не все 8 символов).

Вряд ли вы используете LIKE или =, если вы соответствуете всей строке (и в вашей строке нет символа подстановки). Чтобы сделать поиск нечетким, вам нужно заменить часть шаблона, а не просто добавлять к нему.

Например, чтобы сопоставить последние 7 (вместо 8) символов subcolumn:

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;

Две причины:

  • Он предоставляет оператор подобия %. С его помощью вы можете построить интеллектуальный поиск подобия:

    --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 и %

    Если производительность чтения важнее производительности записи, я предлагаю вам создать function GIN или индекс GiST следующим образом:

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

    Этот индекс поддерживает любой запрос. Имейте в виду, что он поставляется с некоторой стоимостью для операций записи.
    Быстрый тест для аналогичного случая в этом связанном ответе.

Ответ 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);

Ответ 3

Аргумент LIKE - обычная строка, поэтому все строковые манипуляции действительны здесь. В вашем случае вам нужно объединить wildchars с целевой подстрокой, например, @bksi предлагает:

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

Обратите внимание, что такие шаблоны (те, которые начинаются с подстановочного символа %) плохо работают. Взгляните на Изменения производительности PostgreSQL LIKE.

Я бы порекомендовал:

  • придерживаться текущего подхода substr("MainColumn", 13, 8);
  • избегайте LIKE и вместо этого используйте сравнение равенства (=) (хотя они равны, если шаблон LIKE не содержит подстановочных знаков, легче читать запрос);
  • создайте выражение index в "MainTable" следующим образом:

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

Эта комбинация будет лучше работать на мой взгляд.

И используйте имена в нижнем регистре для таблиц/столбцов, чтобы можно было избежать их двойного использования.