2016-06-01 9 views
3

ich eine PostgreSQL-Tabelle und will es mit Fällen hierarchische Ordnung. Hier ein Beispiel:PostgreSQL Bestelltabelle hierarchisch unter Berücksichtigung Bedingungen

> Name | Port 
> ---------------------------- 
> Switch1 | GigabitEthernet2/2 
> Switch1 | GigabitEthernet1/2 
> Switch2 | 1.23 
> Switch2 | 1.21 
> Switch1 | GigabitEthernet2/1 
> Switch1 | GigabitEthernet1/1/3 
> Switch1 | FastEthernet1/1/14 
> Switch1 | FastEthernet3/0/19 
> Switch1 | FastEthernet3/0/20 
> Switch2 | Port-Channel3 
> Switch1 | GigabitEthernet3/0/4 
> Switch1 | GigabitEthernet3/1/3 
> Switch1 | FastEthernet3/0/2 
> Switch2 | 1.14 
> Switch2 | Port-Channel6 

Nach der Bestellung/Sortieranlagen es so sein sollte:

> Name | Port 
> ---------------------------- 
> Switch1 | FastEthernet1/1/14 
> Switch1 | FastEthernet3/0/2 
> Switch1 | FastEthernet3/0/19 
> Switch1 | FastEthernet3/0/20 
> Switch1 | GigabitEthernet1/2 
> Switch1 | GigabitEthernet2/1 
> Switch1 | GigabitEthernet2/2 
> Switch1 | GigabitEthernet1/1/3 
> Switch1 | GigabitEthernet3/0/4 
> Switch1 | GigabitEthernet3/1/3 
> Switch2 | 1.14 
> Switch2 | 1.21 
> Switch2 | 1.23 
> Switch2 | Port-Channel3 
> Switch2 | Port-Channel6 

ich versucht habe, etwas mit ORDER BY CASE zu tun. Hier ein Beispiel:

SELECT device.name, device_port.port 
    FROM device 
    JOIN device_port ON device.ip = device_port.ip 
    ORDER BY CASE WHEN device_port.port like 'Fast%' THEN string_to_array(substr(device_port.port, position('/' in device_port.port)-1),'/')::float[] 
     WHEN device_port.port like 'Gigabit%' THEN string_to_array(substr(device_port.port,16),'/')::float[] 
     WHEN device_port.port like 'Port-channel%' THEN string_to_array(substr(device_port.port,13),'/')::float[] END; 

Aber auf diese Weise gibt es keine Möglichkeit, es zu bestellen zuerst von device.name und namentlich des Hafens. Das Ergebnis wäre zum Beispiel wie:

> Name | Port 
> ---------------------------- 
> Switch1 | FastEthernet1/1/14 
> Switch1 | GigabitEthernet1/2 
> Switch1 | FastEthernet3/0/2 
> Switch1 | GigabitEthernet3/0/4 

Und so weiter ..

jemand eine Idee, wie dieses Problem zu lösen? Habe viele Stunden ohne Ergebnis versucht.

Vielen Dank!

Antwort

2

Verwendung regexp_replace(). Im Beispiel verwende ich zur Vereinfachung eine Tabelle und wähle port_name und port_number zum besseren Verständnis.

select 
    *, 
    regexp_replace(port, '[0-9/\.]', '', 'g') port_name, 
    string_to_array(regexp_replace(port, '[A-Za-z\-]', '', 'g'), '/')::float[] port_number 
from 
    device 
order by 
    name, 
    regexp_replace(port, '[0-9/\.]', '', 'g'), 
    string_to_array(regexp_replace(port, '[A-Za-z\-]', '', 'g'), '/')::float[]; 

    name |   port   | port_name | port_number 
---------+----------------------+-----------------+------------- 
Switch1 | FastEthernet1/1/14 | FastEthernet | {1,1,14} 
Switch1 | FastEthernet3/0/2 | FastEthernet | {3,0,2} 
Switch1 | FastEthernet3/0/19 | FastEthernet | {3,0,19} 
Switch1 | FastEthernet3/0/20 | FastEthernet | {3,0,20} 
Switch1 | GigabitEthernet1/1/3 | GigabitEthernet | {1,1,3} 
Switch1 | GigabitEthernet1/2 | GigabitEthernet | {1,2} 
Switch1 | GigabitEthernet2/1 | GigabitEthernet | {2,1} 
Switch1 | GigabitEthernet2/2 | GigabitEthernet | {2,2} 
Switch1 | GigabitEthernet3/0/4 | GigabitEthernet | {3,0,4} 
Switch1 | GigabitEthernet3/1/3 | GigabitEthernet | {3,1,3} 
Switch2 | 1.14     |     | {1.14} 
Switch2 | 1.21     |     | {1.21} 
Switch2 | 1.23     |     | {1.23} 
Switch2 | Port-Channel3  | Port-Channel | {3} 
Switch2 | Port-Channel6  | Port-Channel | {6} 
(15 rows) 

Option mit int[].

Ich dachte, Sie float[] absichtlich die Art benutzt hatte. Wenn Sie int[] Werte vergleichen wollen (und eine Float-Zahl in einen int-Array konvertieren) können Sie translate() on the fly verwenden:

select 
    *, 
    regexp_replace(port, '[0-9/\.]', '', 'g') port_name, 
    string_to_array(
     regexp_replace(
      translate(port, '.', '/'), 
      '[A-Za-z\-]', '', 'g'), 
     '/')::int[] port_number 
from 
    device 
order by 
    name, 
    regexp_replace(port, '[0-9/\.]', '', 'g'), 
    string_to_array(
     regexp_replace(
      translate(port, '.', '/'), 
      '[A-Za-z\-]', '', 'g'), 
     '/')::int[]; 

    name | port | port_name | port_number 
---------+------+-----------+------------- 
Switch2 | 1.1 |   | {1,1} 
Switch2 | 1.2 |   | {1,2} 
Switch2 | 1.14 |   | {1,14} 
Switch2 | 1.21 |   | {1,21} 
Switch2 | 1.23 |   | {1,23} 
(5 rows) 
0

@klin: Wow so ein einfacher Code und fast wie erwartet funktioniert! Danke vielmals! Wusste nicht, dass solche regulären Ausdrucksfunktionen existieren.

Das einzige, was fehlt, ist die Trennung von {1.14} in ein Array wie {1,14}.

Derzeit nicht die Sortierung zum Beispiel in einer solchen Situation:

> Name | Port 
> ------------------ 
> Switch2 | 1.1 
> Switch2 | 1.18 
> Switch2 | 1.19 
> Switch2 | 1.2 
> Switch2 | 1.20 
> Switch2 | 1.21 

Aber sollte wie

> Name | Port 
> ------------------ 
> Switch2 | 1.1 
> Switch2 | 1.2 
> Switch2 | 1.18 
> Switch2 | 1.19 
> Switch2 | 1.20 
> Switch2 | 1.21 

ich glaube, die Lösung so ähnlich sein sollte:

order by 
    name, 
    regexp_replace(port, '[0-9/\.]', '', 'g'), 
    string_to_array(regexp_replace(port, '[A-Za-z\-]', '', 'g'), '/')::float[], 
    string_to_array(regexp_matches(port, '**finding a . in the string**', **give back full string matching pattern** , 'g'), '.')::float[]; 

Fragen:

1) Können Sie mir helfen, diese regexp_matches-Funktion so zu erstellen, dass sie immer die vollständige Zeichenfolge zurückgibt, wenn sie einen Punkt findet?

2) Was bedeutet die ‚‘ in Ihrem regulären Ausdruck ersetzt Ausdruck bedeuten? Es sollte normalerweise das Ersatzmuster geben.

Nochmals vielen Dank für Ihre Hilfe!

+1

Siehe die bearbeitete Antwort. Die leere Zeichenfolge in 'regexp_replace (port, '[0-9/\.]', '', 'G') bedeutet, dass alle Token, die mit' '[0-9/\.] '' Übereinstimmen, aus' entfernt werden Hafen ". – klin

+0

Ok, das scheint die einfachere Lösung zu sein. Jetzt funktioniert alles wie erwartet. Ich schätze deine Hilfe! – Grunner

Verwandte Themen