Postgresql SELECT, jeśli ciąg zawiera


105

Więc mam w moim Postgresql:

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

Aby uprościć mój problem, chcę wybrać „id” z TAG_TABLE, gdy ciąg „aaaaaaaa” zawiera „nazwa_tagu”. Idealnie więc powinien zwrócić tylko „1”, czyli identyfikator dla nazwy tagu „aaa”

Oto, co robię do tej pory:

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

Ale oczywiście to nie działa, ponieważ postgres uważa, że ​​„% tag_name%” oznacza wzorzec zawierający podciąg „tag_name” zamiast rzeczywistej wartości danych pod tą kolumną.

Jak przekazać tag_name do wzorca?

Odpowiedzi:


131

Powinieneś używać „nazwa_tagu” poza cudzysłowami; następnie jest interpretowane jako pole rekordu. Połącz za pomocą „||” z dosłownymi znakami procentu:

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

5
co się dzieje, gdy nazwa_tagu to "; drop table TAG_TABLE; --"?
Denis de Bernardy

24
@Denis: Nic się nie dzieje. Nie otrzymujesz wiersza, ponieważ wartość WHEREklauzuli wynosi FALSE. Instrukcja nie jest dynamiczna, tylko wartości są łączone, nie ma szans na wstrzyknięcie SQL.
Erwin Brandstetter

1
czy kolejność aaaa i nazwa_tagu nie powinna być odwrócona? mam na myśli, że powinieneś wstawić nazwę kolumny, po której
user151496

@ user151496 Nie, ponieważ wzorzec musi znajdować się po prawej stronie LIKEsłowa kluczowego.
jpmc26

4
Pamiętaj, że używanie zmiennych we LIKEwzorcu może mieć niezamierzone konsekwencje, gdy te zmienne zawierają podkreślenia (_) lub znaki procentu (%). Może być konieczna zmiana znaczenia tych znaków, na przykład za pomocą tej funkcji: CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;(od użytkownika MatheusOl z kanału IRC #postgresql na Freenode).
Martin von Wittich

46

Osobiście wolę prostszą składnię operatora ~.

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

Warto przeczytać Różnicę między LIKE i ~ w Postgres, aby zrozumieć różnicę. `


2
Działa to tylko wtedy, gdy tag_namejest to właściwy REGEX. Dość ryzykowne.
Jakub Fedyczak

@JakubFedyczak, aby dopasować dosłowną nazwę tagu, której możesz użyć, o ***=której mowa w postgresql.org/docs/current/static/functions-matching.html . Jednak okazało się, że jest to zbyt wolniejsze w porównaniu z rozwiązaniami strpos/ position.
phunehehe

27

Odpowiedni sposób wyszukać podciągu jest użycie positionfunkcji zamiast likewyrazu, który wymaga ucieczki %, _a charakter ucieczki ( \domyślnie):

SELECT id FROM TAG_TABLE WHERE position(tag_name in 'aaaaaaaaaaa')>0;

To jest właściwy sposób, aby to zrobić. Nikt nie powinien używać hacky regex.
khol

LIKEi ILIKEpotrafi używać ginindeksów. positionNie mogę.
Eugene Pakhomov

14

Oprócz rozwiązania z 'aaaaaaaa' LIKE '%' || tag_name || '%'there are position(odwrócona kolejność argumentów) istrpos .

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

Poza tym, co jest bardziej wydajne (LIKE wygląda na mniej wydajne, ale indeks może coś zmienić), istnieje bardzo drobny problem z LIKE: nazwa_tagu oczywiście nie powinien zawierać, %a zwłaszcza _(pojedynczy znak wieloznaczny), aby nie dawać fałszywych alarmów.


2
Musiałem zastąpić strpos pozycją, ponieważ strpos zawsze zwracał mi 0
jcf

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

tag_name powinno być w cudzysłowie, w przeciwnym razie zwróci błąd, ponieważ nazwa_tagu nie istnieje


2
To jest dokładnie przeciwieństwo zaakceptowanej odpowiedzi . Łączysz jako ciąg, podczas gdy musi to być kolumna ...
Suraj Rao
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.