Postgresql SELECT dizesi içeriyorsa


108

Postgresql'imde bir var:

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

Sorunumu basitleştirmek için, yapmak istediğim şey, bir "aaaaaaaa" dizesi 'etiket_adı' içerdiğinde TAG_TABLE'dan 'id' öğesini SEÇMEK. Bu nedenle ideal olarak, yalnızca 'aaa' etiket adının kimliği olan "1" döndürmelidir

Şu ana kadar yaptığım şey bu:

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

Ancak postgres, '% tag_name%' ifadesinin o sütunun altındaki gerçek veri değeri yerine 'tag_name' alt dizesini içeren bir kalıp anlamına geldiğini düşündüğü için açıkçası bu işe yaramaz.

Tag_name'yi kalıba nasıl aktarırım?

Yanıtlar:


135

Tırnakların dışında 'tag_name' kullanmalısınız; daha sonra kaydın bir alanı olarak yorumlanır. '||' kullanarak birleştirin gerçek yüzde işaretleriyle:

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

5
tag_name olduğunda hapoens nedir "; drop table TAG_TABLE; --"?
Denis de Bernardy

24
@Denis: Hiçbir şey olmuyor. Yan WHEREtümce olarak değerlendirildiği için satır almazsınız FALSE. İfade dinamik değildir, yalnızca değerler birleştirilir, SQL enjeksiyonu şansı yoktur.
Erwin Brandstetter

1
aaaa ve tag_name sırası tersine çevrilmemelidir? Demek istediğim, bundan sonra bir sütun adı
koymalısınız

@ user151496 Hayır, çünkü şablon LIKEanahtar kelimenin sağ tarafında yer almalıdır .
jpmc26

4
Bir LIKEmodelde değişkenler kullanmanın , bu değişkenler alt çizgi (_) veya yüzde karakterleri (%) içerdiğinde istenmeyen sonuçlara yol açabileceğine dikkat edin . Bu karakterlerden CREATE OR REPLACE FUNCTION quote_for_like(text) RETURNS text LANGUAGE SQL IMMUTABLE AS $$ SELECT regexp_replace($1, '([\%_])', '\\\1', 'g'); $$;kaçınmak gerekebilir, örneğin şu işlevle: (Freenode'daki #postgresql IRC kanalından MatheusOl kullanıcısından).
Martin von Wittich

46

Ben şahsen ~ operatörünün daha basit sözdizimini tercih ederim.

SELECT id FROM TAG_TABLE WHERE 'aaaaaaaa' ~ tag_name;

Farkı anlamak için Postgres'te LIKE ve ~ arasındaki Fark'ı okumaya değer . '


2
Bu, yalnızca tag_nameuygun bir REGEX olduğunda çalışır . Oldukça riskli.
Jakub Fedyczak

@JakubFedyczak ***=, postgresql.org/docs/current/static/functions-matching.html'de belirtilen , kullanabileceğiniz literal tag_name ile eşleşecek . Bununla birlikte, strpos/ positionçözümlerine kıyasla bunun çok daha yavaş olduğunu buldum .
phunehehe

28

Bir alt dize aramak için bir uygun yolu kullanımı için positionyerine fonksiyonu likekaçan gerektirir ifadesi %, _ve (çıkış karakteri \varsayılan olarak):

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

Bunu yapmanın doğru yolu budur. Hiç kimse hacky regex yaklaşımlarını kullanmamalıdır.
khol

LIKEve endeksleri ILIKEkullanabilir gin. positionolumsuz.
Eugene Pakhomov

14

Çözüme ek 'aaaaaaaa' LIKE '%' || tag_name || '%'olarak position(değiştirilmiş argüman sırası) ve strpos.

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

Neyin daha verimli olduğunun yanı sıra (LIKE daha az verimli görünüyor, ancak bir dizin bazı şeyleri değiştirebilir), LIKE: tag_name ile ilgili çok küçük bir sorun var elbette %ve özellikle _(tek karakter joker karakteri) yanlış pozitifler vermemelidir.


2
Strpos

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

tag_name tırnak içinde olmalıdır, aksi takdirde etiket_adı mevcut olmadığından hata verecektir


2
Bu, kabul edilen cevabın tam tersi . Sütun olması gerekirken dize olarak birleştiriyorsunuz ...
Suraj Rao
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.