Postgresql SELECT, если строка содержит

108

Итак, в моем Postgresql есть:

TAG_TABLE
==========================
id            tag_name       
--------------------------
1             aaa
2             bbb
3             ccc

Чтобы упростить мою проблему, я хочу выбрать «id» из TAG_TABLE, когда строка «aaaaaaaa» содержит «tag_name». Поэтому в идеале он должен возвращать только "1", который является идентификатором имени тега 'aaa'.

Вот чем я пока занимаюсь:

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaaaaa' LIKE '%tag_name%'

Но очевидно, что это не работает, поскольку postgres считает, что «% tag_name%» означает шаблон, содержащий подстроку «tag_name» вместо фактического значения данных в этом столбце.

Как передать tag_name в шаблон ??

user2436815
источник

Ответы:

135

Вы должны использовать «tag_name» вне кавычек; затем он интерпретируется как поле записи. Объединить с помощью '||' с буквенными знаками процента:

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' LIKE '%' || tag_name || '%';
Франс ван Буул
источник
5
что hapoens когда tag_name есть "; drop table TAG_TABLE; --"?
Дени де Бернарди
24
@ Денис: Ничего не происходит. У вас нет строки, потому что WHEREпредложение оценивается как FALSE. Оператор не является динамическим, объединяются только значения, нет возможности для SQL-инъекции.
Эрвин Брандштеттер,
1
не должен быть обратный порядок aaaa и tag_name? я имею в виду, что вы должны поставить имя столбца после where
user151496
@ user151496 Нет, потому что шаблон должен располагаться справа от LIKEключевого слова.
jpmc26
4
Помните, что использование переменных в LIKEшаблоне может иметь непредвиденные последствия, если эти переменные содержат символы подчеркивания (_) или символы процента (%). Может потребоваться экранировать эти символы, например, с помощью этой функции: CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;(от пользователя MatheusOl из IRC-канала #postgresql на Freenode).
Мартин фон Виттих
46

Лично я предпочитаю более простой синтаксис оператора ~.

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

Стоит прочитать Разница между LIKE и ~ в Postgres, чтобы понять разницу. `

Keithhackbarth
источник
2
Это работает только при tag_nameправильном REGEX. Довольно рискованно.
Якуб Федычак
@JakubFedyczak для соответствия буквальному имени тега, которое вы можете использовать, ***=которое упоминается в postgresql.org/docs/current/static/functions-matching.html . Однако я обнаружил, что это намного медленнее по сравнению с strpos/ positionsolutions.
phunehehe
28

Правильный путь для поиска подстроки является использование positionфункции вместо likeвыражения, которое требует побега %, _и экранирующего символ ( \по умолчанию):

SELECT id FROM TAG_TABLE WHERE position(tag_name in 'aaaaaaaaaaa')>0;
Томецкий
источник
Это правильный способ сделать это. Никто не должен использовать хакерские подходы к регулярным выражениям.
хол
LIKEи ILIKEможет использовать ginиндексы. positionне может.
Евгений Пахомов
14

В дополнение к решению с 'aaaaaaaa' LIKE '%' || tag_name || '%'существуют position(обратный порядок аргументов) и strpos.

SELECT id FROM TAG_TABLE WHERE strpos('aaaaaaaa', tag_name) > 0

Помимо того, что более эффективно (LIKE выглядит менее эффективным, но индекс может изменить ситуацию), с LIKE есть очень небольшая проблема: tag_name, конечно, не должен содержать, %и особенно _(одиночный символ подстановки), чтобы не давать ложных срабатываний.

Юп Эгген
источник
2
Мне пришлось заменить strpos на position, поскольку strpos всегда возвращал для меня 0
jcf
-2
SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' LIKE '%' || "tag_name" || '%';

tag_name должен быть в цитате, иначе будет выдана ошибка, так как tag_name не существует

Светлана Верма
источник
2
Это полная противоположность принятому ответу . Вы объединяете как строку, в то время как она должна быть столбцом ...
Сурадж Рао