Обсуждение: Sorting router interfaces
I am trying to sort router interface names.
The problem is that I am doing a text sort and need to do a numerical sort.
I want the interfaces to be in numerical order:
GigabitEthernet1/0/1 | 1/0/1 | {1,0,1}
GigabitEthernet1/0/2 | 1/0/2 | {1,0,2}
GigabitEthernet1/0/3 | 1/0/3 | {1,0,3}
etc.....
What I get instead is the following text ordering:
GigabitEthernet1/0/1 | 1/0/1 | {1,0,1}
GigabitEthernet1/0/10 | 1/0/10 | {1,0,10}
GigabitEthernet1/0/11 | 1/0/11 | {1,0,11}
GigabitEthernet1/0/12 | 1/0/12 | {1,0,12}
GigabitEthernet1/0/13 | 1/0/13 | {1,0,13}
GigabitEthernet1/0/14 | 1/0/14 | {1,0,14}
GigabitEthernet1/0/15 | 1/0/15 | {1,0,15}
GigabitEthernet1/0/16 | 1/0/16 | {1,0,16}
GigabitEthernet1/0/17 | 1/0/17 | {1,0,17}
GigabitEthernet1/0/18 | 1/0/18 | {1,0,18}
GigabitEthernet1/0/19 | 1/0/19 | {1,0,19}
GigabitEthernet1/0/2 | 1/0/2 | {1,0,2}
GigabitEthernet1/0/20 | 1/0/20 | {1,0,20}
GigabitEthernet1/0/21 | 1/0/21 | {1,0,21}
GigabitEthernet1/0/22 | 1/0/22 | {1,0,22}
GigabitEthernet1/0/23 | 1/0/23 | {1,0,23}
GigabitEthernet1/0/24 | 1/0/24 | {1,0,24}
GigabitEthernet1/0/25 | 1/0/25 | {1,0,25}
GigabitEthernet1/0/26 | 1/0/26 | {1,0,26}
GigabitEthernet1/0/27 | 1/0/27 | {1,0,27}
GigabitEthernet1/0/28 | 1/0/28 | {1,0,28}
GigabitEthernet1/0/29 | 1/0/29 | {1,0,29}
GigabitEthernet1/0/3 | 1/0/3 | {1,0,3}
GigabitEthernet1/0/30 | 1/0/30 | {1,0,30}
GigabitEthernet1/0/31 | 1/0/31 | {1,0,31}
GigabitEthernet1/0/32 | 1/0/32 | {1,0,32}
GigabitEthernet1/0/33 | 1/0/33 | {1,0,33}
FYI: I also have entries like the following:
lc-5/2/0.32769 | 5/2/0.32769 | {5,2,0.32769}
irb.5 | .5 | {.5}
irb.51 | .51 | {.51}
irb.52 | .52 | {.52}
ae6 | 6 | {6}
ae7 | 7 | {7}
lo0.0 | 0.0 | {0.0}
Vlan710 | 710 | {710}
Vlan760 | 760 | {760}
Vlan910 | 910 | {910}
Vlan910 | 910 | {910}
gre | | {""}
tap | | {""}
dsc | | {""}
The above listings are produced with the following:
SELECT
interface,
regexp_replace(interface,'[A-Za-z -]+','','g') as "sort_col1",
regexp_split_to_array(regexp_replace(interface,'[A-Za-z
-]+','','g'),E'/') as "sort_col"
FROM all_ports
ORDER BY devicename,sort_col
I have tried to break out the interface number to a separate array
column to sort on and was hoping to cast the array to a float[], but
no luck:
SELECT
interface,
regexp_replace(interface,'[A-Za-z -]+','','g') as "sort_col1",
regexp_split_to_array(regexp_replace(interface,'[A-Za-z
-]+','','g'),E'/')::float as "sort_col"
FROM all_ports
psql:-:15: ERROR: cannot cast type text[] to double precision
LINE 5: ...gexp_replace(interface,'[A-Za-z -]+','','g'),E'/')::float as...
Can anyone suggest a better approach or help with this approach?
Thanks
2010/11/1 Brian Sherwood <bdsher@gmail.com>:
> I am trying to sort router interface names.
> The problem is that I am doing a text sort and need to do a numerical sort.
>
> I want the interfaces to be in numerical order:
>
> GigabitEthernet1/0/1 | 1/0/1 | {1,0,1}
> GigabitEthernet1/0/2 | 1/0/2 | {1,0,2}
> GigabitEthernet1/0/3 | 1/0/3 | {1,0,3}
> etc.....
>
>
> What I get instead is the following text ordering:
>
> GigabitEthernet1/0/1 | 1/0/1 | {1,0,1}
> GigabitEthernet1/0/10 | 1/0/10 | {1,0,10}
> GigabitEthernet1/0/11 | 1/0/11 | {1,0,11}
> GigabitEthernet1/0/12 | 1/0/12 | {1,0,12}
> GigabitEthernet1/0/13 | 1/0/13 | {1,0,13}
> GigabitEthernet1/0/14 | 1/0/14 | {1,0,14}
> GigabitEthernet1/0/15 | 1/0/15 | {1,0,15}
> GigabitEthernet1/0/16 | 1/0/16 | {1,0,16}
> GigabitEthernet1/0/17 | 1/0/17 | {1,0,17}
> GigabitEthernet1/0/18 | 1/0/18 | {1,0,18}
> GigabitEthernet1/0/19 | 1/0/19 | {1,0,19}
> GigabitEthernet1/0/2 | 1/0/2 | {1,0,2}
> GigabitEthernet1/0/20 | 1/0/20 | {1,0,20}
> GigabitEthernet1/0/21 | 1/0/21 | {1,0,21}
> GigabitEthernet1/0/22 | 1/0/22 | {1,0,22}
> GigabitEthernet1/0/23 | 1/0/23 | {1,0,23}
> GigabitEthernet1/0/24 | 1/0/24 | {1,0,24}
> GigabitEthernet1/0/25 | 1/0/25 | {1,0,25}
> GigabitEthernet1/0/26 | 1/0/26 | {1,0,26}
> GigabitEthernet1/0/27 | 1/0/27 | {1,0,27}
> GigabitEthernet1/0/28 | 1/0/28 | {1,0,28}
> GigabitEthernet1/0/29 | 1/0/29 | {1,0,29}
> GigabitEthernet1/0/3 | 1/0/3 | {1,0,3}
> GigabitEthernet1/0/30 | 1/0/30 | {1,0,30}
> GigabitEthernet1/0/31 | 1/0/31 | {1,0,31}
> GigabitEthernet1/0/32 | 1/0/32 | {1,0,32}
> GigabitEthernet1/0/33 | 1/0/33 | {1,0,33}
>
>
> FYI: I also have entries like the following:
> lc-5/2/0.32769 | 5/2/0.32769 | {5,2,0.32769}
> irb.5 | .5 | {.5}
> irb.51 | .51 | {.51}
> irb.52 | .52 | {.52}
> ae6 | 6 | {6}
> ae7 | 7 | {7}
> lo0.0 | 0.0 | {0.0}
> Vlan710 | 710 | {710}
> Vlan760 | 760 | {760}
> Vlan910 | 910 | {910}
> Vlan910 | 910 | {910}
> gre | | {""}
> tap | | {""}
> dsc | | {""}
>
>
> The above listings are produced with the following:
>
> SELECT
> interface,
> regexp_replace(interface,'[A-Za-z -]+','','g') as "sort_col1",
> regexp_split_to_array(regexp_replace(interface,'[A-Za-z
> -]+','','g'),E'/') as "sort_col"
> FROM all_ports
> ORDER BY devicename,sort_col
>
>
> I have tried to break out the interface number to a separate array
> column to sort on and was hoping to cast the array to a float[], but
> no luck:
>
> SELECT
> interface,
> regexp_replace(interface,'[A-Za-z -]+','','g') as "sort_col1",
> regexp_split_to_array(regexp_replace(interface,'[A-Za-z
> -]+','','g'),E'/')::float as "sort_col"
> FROM all_ports
>
> psql:-:15: ERROR: cannot cast type text[] to double precision
> LINE 5: ...gexp_replace(interface,'[A-Za-z -]+','','g'),E'/')::float as...
>
>
>
> Can anyone suggest a better approach or help with this approach?
good approach, jus needed to be generalized...
filip@filip=# SELECT interface,
regexp_replace( interface, '[0-9].*', '' ) as before_1st_digit,
regexp_replace( interface, '^[^0-9]+', '' ) as from_first_digit,
CASE WHEN interface ~ '[0-9]' THEN regexp_split_to_array( regexp_replace( interface, '^[^0-9]+', ''
), '[^0-9]+' )::int[]
ELSE array[-1] END as nums
FROM interfaces
ORDER BY 2,4;
interface | before_1st_digit | from_first_digit | nums
-----------------------+------------------+------------------+----------eth0 | eth | 0
| {0}eth0/0 | eth | 0/0 | {0,0}eth0/1 | eth
| 0/1 | {0,1}eth0/10 | eth | 0/10 | {0,10}eth1
|eth | 1 | {1}GigabitEthernet1/0/2 | GigabitEthernet | 1/0/2 |
{1,0,2}GigabitEthernet1/0/20| GigabitEthernet | 1/0/20 | {1,0,20}irb.5 | irb. |
5 | {5}irb.51 | irb. | 51 | {51}tun | tun
| | {-1}tun0 | tun | 0 | {0}Vlan72
|Vlan | 72 | {72}Vlan710 | Vlan | 710 | {710}
(13 rows)
--
Filip Rembiałkowski
JID,mailto:filip.rembialkowski@gmail.com
http://filip.rembialkowski.net/
Am 01.11.2010 13:15, schrieb Brian Sherwood:
> I am trying to sort router interface names.
> The problem is that I am doing a text sort and need to do a numerical sort.
>
>
> What I get instead is the following text ordering:
>
> GigabitEthernet1/0/1 | 1/0/1 | {1,0,1}
> GigabitEthernet1/0/10 | 1/0/10 | {1,0,10}
> GigabitEthernet1/0/11 | 1/0/11 | {1,0,11}
> GigabitEthernet1/0/12 | 1/0/12 | {1,0,12}
> GigabitEthernet1/0/13 | 1/0/13 | {1,0,13}
This was the easy part.
Suppose those lines above were the input table "interfaces" and the
columns were called c1, c2, c3.
Since c3 is allready an array you could do this:
select *
from interfaces
order by (c3::integer[])[1], (c3::integer[])[2], (c3::integer[])[3]
Records of this type
> lc-5/2/0.32769 | 5/2/0.32769 | {5,2,0.32769}
work with:
order by (c3::float[])[1], (c3::float[])[2], (c3::float[])[3]
Now you "just" need to identify those records which wont produce such
nice numerical arrays.
Then split the two sets up, sort them in separate selects, add a set_nr
and a row_number() as row_nr.
Then UNION both sets together again
AND eventually do an ORDER BY set_nr, row_nr
and you are allready done.
OK, that would be just an idea :)