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?

user2436815
źródło

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 || '%';
Frans van Buul
źródło
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ę. `

keithhackbarth
źródło
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;
Tometzky
źródło
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.

Joop Eggen
źródło
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

Shweta Verma
źródło
2
To jest dokładnie przeciwieństwo zaakceptowanej odpowiedzi . Łączysz jako ciąg, podczas gdy musi to być kolumna ...
Suraj Rao