2013-10-07 3 views
8

Ich möchte eine elegante Möglichkeit finden, das Verhalten der MySQL subtring_index() Funktion in Postgres zu emulieren.Emulation von MySQL substring_index() in PGSQL

In MySQL, dann ist es so einfach wie:

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) 

Aber meine aktuelle Arbeit um in PGSQL ziemlich hässlich ist:

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) 

Vielleicht gibt es eine elegantere Lösung, die einen regulären Ausdruck verwenden, oder vielleicht selbst wenn ich die Zeichenkette in ein Array in einer Variablen aufspalte, was den Overhead reduzieren könnte, wenn die Zeichenkette von einer Unterabfrage oder etwas abgeleitet wäre, würde ich alle Vorschläge begrüßen.

+2

Ich nehme an, dass die Lösung von außen die Daten so speichert, dass sie besser zu den Abfragen passen, die Sie ausführen möchten (z. B. durch Normalisieren oder Verwenden eines Array-Typs). Mir ist klar, dass das nicht immer eine Option ist, aber ich dachte, ich würde es da rauswerfen, zumal dein MySQL-Beispiel speziell für die Aufteilung in genau 2 Teile codiert zu sein scheint. – IMSoP

Antwort

10

Nehmen Sie sich immer die Zeit, um die Handbücher zu überfliegen.

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

Wenn split_part(string text, delimiter text, field int) nicht tun, was Sie wollen (und mehr, wenn ich Ihre MySQL-Funktion zu verstehen), dann werden Sie erklären müssen, wo und warum.

+1

Ah, das Handbuch scheint "String-Funktionen und Operatoren" mit "anderen String-Funktionen" zu trennen, das war in letzterem was ich anscheinend übersehen habe. Vielen Dank. –

+0

@jesse_galley: ["Einige von ihnen werden intern verwendet, um die in Tabelle 9-5 aufgeführten ** SQL-Standard ** -String-Funktionen zu implementieren."] (Http://www.postgresql.org/docs/current/static/ functions-string.html) [Betonung meiner]. Die erste Liste soll also die vom SQL-Standard spezifizierten Funktionen abdecken, während die zweite die PostgreSQL-Erweiterungen abdecken soll. –

+1

Obwohl SPLIT_PART das oben gezeigte Beispiel löst, ist es kein Tool zum Emulieren von MySQL SUBSTRING_INDEX, da SUBSTRING_INDEX die Teilzeichenfolge links oder rechts von einer angegebenen Anzahl von Vorkommen eines Trennzeichens zurückgibt. Wie kann man das Verhalten emulieren, wenn eine zufällige Anzahl von Vorkommen eines Trennzeichens auftritt? Zum Beispiel, die Domain aus einem größeren Teil einer URL auswählen; Beispiel: Wählen Sie "domain.com" aus "sports.adventures.hobbies.domain.com" und auch "pets.domain.com" aus. Um dieses Problem in PostgreSQL zu lösen, benötigen wir wahrscheinlich Reg-Ausdrücke oder die Kombination verschiedener String-Funktionen. –

1

Hier ist, wie ich implementieren (oder emulieren) MySQL subtring_index() 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; 

und hier ist das Beispiel von MySQL-Dokumentation;