Xây dựng dựa trên dữ liệu thử nghiệm của bạn, nhưng điều này hoạt động với dữ liệu tùy ý. Điều này hoạt động với bất kỳ số phần tử nào trong chuỗi.
Đăng ký một kiểu kết hợp được tạo thành từ một text
và một integer
giá trị một lần cho mỗi cơ sở dữ liệu. Tôi gọi nó là ai
:
CREATE TYPE ai AS (a text, i int);
Bí quyết là tạo một mảng ai
từ mỗi giá trị trong cột.
regexp_matches()
với mẫu (\D*)(\d*)
và g
tùy chọn trả về một hàng cho mọi kết hợp chữ cái và số. Cộng với một hàng lủng lẳng không liên quan với hai chuỗi trống '{"",""}'
Việc lọc hoặc loại bỏ nó sẽ chỉ làm tăng thêm chi phí. Tổng hợp giá trị này thành một mảng, sau khi thay thế các chuỗi trống (''
) với 0
trong integer
thành phần (dưới dạng ''
không thể chuyển thành integer
).
NULL
các giá trị sắp xếp trước - hoặc bạn phải viết hoa chữ thường đặc biệt - hoặc sử dụng toàn bộ trong một STRICT
chức năng như @Craig đề xuất.
Postgres 9.4 trở lên
SELECT data
FROM alnum
ORDER BY ARRAY(SELECT ROW(x[1], CASE x[2] WHEN '' THEN '0' ELSE x[2] END)::ai
FROM regexp_matches(data, '(\D*)(\d*)', 'g') x)
, data;
db <> fiddle here
Postgres 9.1 (câu trả lời gốc)
Đã kiểm tra với PostgreSQL 9.1.5, trong đó regexp_replace()
có một hành vi hơi khác.
SELECT data
FROM (
SELECT ctid, data, regexp_matches(data, '(\D*)(\d*)', 'g') AS x
FROM alnum
) x
GROUP BY ctid, data -- ctid as stand-in for a missing pk
ORDER BY regexp_replace (left(data, 1), '[0-9]', '0')
, array_agg(ROW(x[1], CASE x[2] WHEN '' THEN '0' ELSE x[2] END)::ai)
, data -- for special case of trailing 0
Thêm regexp_replace (left(data, 1), '[1-9]', '0')
dưới dạng ORDER BY
đầu tiên mục để quan tâm đến các chữ số đứng đầu và chuỗi trống.
Nếu các ký tự đặc biệt như Đề xuất của {}()"',
có thể xảy ra, bạn phải thoát khỏi những điều đó cho phù hợp.
@ Craig để sử dụng ROW
biểu thức đảm nhận điều đó.
BTW, điều này sẽ không thực thi trong sqlfiddle, nhưng nó thực hiện trong cụm db của tôi. JDBC không phụ thuộc vào nó. sqlfiddle phàn nàn:
Phương thức org.postgresql.jdbc3.Jdbc3Array.getArrayImpl (long, int, Map) chưa được triển khai.
Điều này đã được khắc phục sau đó:http://sqlfiddle.com/#!17/fad6e/1