Postgresql SELECT, якщо рядок містить


105

Отже, у мене в моєму Postgresql:

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

Щоб спростити свою проблему, те, що я хочу зробити, це SELECT 'id' від TAG_TABLE, коли рядок "aaaaaaaa" містить "tag_name". Тому в ідеалі він повинен повертати лише "1", що є ідентифікатором для імені тега "aaa"

Це я зараз роблю:

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

Але очевидно, що це не працює, оскільки постгреси вважають, що "% tag_name%" означає шаблон, що містить підрядку "tag_name" замість фактичного значення даних у цьому стовпці.

Як передати тег_імен до шаблону ??

Відповіді:


131

Ви повинні використовувати 'tag_name' поза лапок; то його інтерпретують як поле запису. Об’єднайте, використовуючи "||" з буквальними знаками відсотка:

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' LIKE '%' || tag_name || '%';

5
що означає галогени, коли тег_назви "; drop table TAG_TABLE; --"?
Дені де Бернарді

24
@Denis: Нічого не відбувається. Ви не отримуєте жодного рядка, оскільки WHEREстаття оцінює до FALSE. Оператор не динамічний, лише значення об'єднані, шансу для ін'єкції SQL немає.
Ервін Брандстеттер

1
чи не повинен бути порядок аааа та тегу_міни перетворений? я маю на увазі, що слід вказати ім'я стовпця після того, де
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, щоб зрозуміти різницю. `


2
Це працює лише тоді, коли tag_nameє належним REGEX. Досить ризиковано.
Якуб Федичак

@JakubFedyczak, щоб відповідати буквальному тегу_імен, який ви можете використовувати, ***=який згадується в postgresql.org/docs/current/static/functions-matching.html . Однак я виявив, що це занадто повільніше порівняно з strpos/ positionрішеннями.
phunehehe

27

Правильний спосіб пошуку підрядків - це використання 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, звичайно, не повинна містити, %а особливо _(одиночна підстановка для символів char), щоб не містити помилкових позитивних результатів.


2
Мені довелося замінити strpos на позицію, оскільки strpos завжди повертав 0 для мене
jcf

-2
SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' LIKE '%' || "tag_name" || '%';

tag_name має бути в котируванні, інакше це призведе до помилки, оскільки тест_імен не існує


2
Це якраз протилежна прийнятій відповіді . Ви об'єднуєтесь як рядок, тоді як це має бути стовпець ...
Suraj Rao
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.