问题
I have the following sample data for a particular column symbol for sample table.
(Update:) The data is not in a regular pattern. Number may occur at any place in between characters.
symbol
COL4A1
COL4A3
COL8A2
COL2A1
COL12A1
COL12A1
COL16A1
COL19A1
I need to sort the this data on database level. I used the following query:
select symbol from sample order by symbol asc
Result is follows:
COL12A1
COL12A1
COL16A1
COL19A1
COL2A1
COL4A1
COL4A3
COL8A2
But I need to get the order in the following way:
COL2A1
COL4A1
COL4A3
COL8A2
COL12A1
COL12A1
COL16A1
COL19A1
回答1:
PostgreSQL doesn't offer a number-aware collation that can do "humanized" sorts like "1A, 2A, 3A, ... 10A, 11A, ...". It relies on the operating system for collation, and I'm not aware of any OS that exposes such a collation to applications.
To do this, you need to split the text according to a pattern and order by the pattern parts, probably using regexp_matches.
CREATE TABLE Table1 ("symbol" text);
INSERT INTO Table1 ("symbol") VALUES
('COL4A1'),('COL4A3'),('COL8A2'),('COL2A1'),
('COL12A1'),('COL12A1'),('COL16A1'),('COL19A1');
WITH matched(symbol, symbol_parts) AS (
SELECT symbol, regexp_matches(symbol, '(\D*)(\d+)(\D+)(\d+)')
FROM Table1
)
SELECT symbol
FROM matched
ORDER BY symbol_parts[1], symbol_parts[2]::integer,
symbol_parts[3], symbol_parts[4]::integer;
回答2:
CREATE OR REPLACE FUNCTION pad_numbers(text)
RETURNS text AS
$BODY$
SELECT regexp_replace(
regexp_replace(
regexp_replace(
regexp_replace(
$1,
E'(^|\\D)(\\d{1,3}($|\\D))', E'\\1000\\2', 'g'
), E'(^|\\D)(\\d{4,6}($|\\D))', E'\\1000\\2', 'g'
), E'(^|\\D)(\\d{7}($|\\D))', E'\\100\\2', 'g'
), E'(^|\\D)(\\d{8}($|\\D))', E'\\10\\2', 'g'
);
$BODY$
LANGUAGE 'sql' VOLATILE;
select symbol from sample order by pad_numbers(symbol) asc
来源:https://stackoverflow.com/questions/12916212/how-to-do-sorting-on-irregular-alphanumeric-data-in-postgres-sql