2013-10-07 10 views
8

Mi piacerebbe trovare un modo elegante per emulare il comportamento della funzione subtring_index() di MySQL in Postgres.emulazione di substring_index() di MySQL in PGSQL

In MySQL, è facile come:

mysql> create temporary table test1(test varchar(200)); 
Query OK, 0 rows affected (0.01 sec) 

mysql> insert into test1 values('apples||oranges'),('apples||grapes'); 
Query OK, 2 rows affected (0.00 sec) 
Records: 2 Duplicates: 0 Warnings: 0 

mysql> select * from test1; 
+-----------------+ 
| test   | 
+-----------------+ 
| apples||oranges | 
| apples||grapes | 
+-----------------+ 
2 rows in set (0.00 sec) 

mysql> select substring_index(test, '||', 1) as field1, substring_index(test, '||', -1) as field2 from test1; 
+--------+---------+ 
| field1 | field2 | 
+--------+---------+ 
| apples | oranges | 
| apples | grapes | 
+--------+---------+ 
2 rows in set (0.00 sec) 

Ma il mio lavoro attuale in giro in PGSQL è abbastanza brutto:

hoth=# create temporary table test1(test text); 
CREATE TABLE 

hoth=# insert into test1 values('apples||oranges'),('apples||grapes'); 
INSERT 0 2 

hoth=# select * from test1; 
     test  
----------------- 
apples||oranges 
apples||grapes 
(2 rows) 

hoth=# select substring(test, 0, position('||' in test)) as field1, substring(test, position('||' in test) + 2, char_length(test)) as field2 from test1; 
field1 | field2 
--------+--------- 
apples | oranges 
apples | grapes 
(2 rows) 

forse c'è una soluzione più elegante utilizzando un'espressione regolare, o forse anche suddividendo la stringa in una matrice in una variabile che potrebbe ridurre il sovraccarico se la stringa deriva da una sottoquery o qualcosa del genere, accolgo con favore qualsiasi suggerimento.

+2

Suppongo che la soluzione al di fuori-the-box è quello di memorizzare i dati in un modo che è più suscettibili alle domande che si desidera eseguire (ad esempio normalizzando o usando un tipo di matrice). Mi rendo conto che non è sempre un'opzione, ma ho pensato di buttarla lì, in particolare perché il tuo esempio MySQL sembra essere specificamente codificato per la suddivisione in esattamente 2 parti. – IMSoP

risposta

10

Prendersi sempre del tempo per sfogliare i manuali.

http://www.postgresql.org/docs/current/static/functions-string.html

Se split_part(string text, delimiter text, field int) non fa ciò che si vuole (e di più, se ho ben capito la funzione MySQL) allora avrete bisogno di spiegare dove e perché.

+1

Ah, il manuale sembra separare "funzioni stringa e operatori" con "altre funzioni stringa", questo era in quest'ultimo caso che apparentemente trascurato. Grazie. –

+0

@jesse_galley: ["Alcuni di questi sono utilizzati internamente per implementare le ** funzioni di stringa ** standard SQL elencate nella Tabella 9-5."] (Http://www.postgresql.org/docs/current/static/ functions-string.html) [enfasi mia]. Quindi il primo elenco è destinato a coprire le funzioni specificate dallo standard SQL mentre il secondo è destinato a coprire le estensioni di PostgreSQL. –

+1

Sebbene SPLIT_PART risolva l'esempio mostrato sopra, non è uno strumento per emulare il SUBSTRING_INDEX di MySQL, dato che SUBSTRING_INDEX restituisce la sottostringa a sinistra oa destra di un numero specificato di occorrenze di un delimitatore. Come emulare il suo comportamento quando si trova di fronte a un numero arbitrario di occorrenze di un delimitatore? Ad esempio, selezionando il dominio da una parte più ampia di un URL; ad esempio selezionando "dominio.com" da "sports.adventures.hobbies.domain.com" e anche da "pets.domain.com"? Per risolvere questo problema in PostgreSQL probabilmente abbiamo bisogno di espressioni di reg o di combinare varie funzioni di stringa. –

1

Ecco come a implementare (o emulare) subtring_index di MySQL() in PostgreSQL

CREATE OR REPLACE FUNCTION public.substring_index (
    str text, 
    delim text, 
    count integer = 1, 
    out substring_index text 
) 
RETURNS text AS 
$body$ 
BEGIN 
    IF count > 0 THEN 
    substring_index = array_to_string((string_to_array(str, delim))[:count], delim); 
    ELSE 
    DECLARE 
     _array TEXT[]; 
    BEGIN 
     _array = string_to_array(str, delim); 
     substring_index = array_to_string(_array[array_length(_array, 1) + count + 1:], delim);  
    END; 
    END IF; 
END; 
$body$ 
LANGUAGE 'plpgsql' 
IMMUTABLE 
CALLED ON NULL INPUT 
SECURITY INVOKER 
COST 5; 

e qui è l'esempio dalla documentazione di MySQL;

postgres=# SELECT substring_index('www.mysql.com', '.', 2); 
substring_index 
----------------- 
www.mysql 
(1 row) 

postgres=# SELECT substring_index('www.mysql.com', '.', -2); 
substring_index 
----------------- 
mysql.com 
(1 row)