Hoàn toàn có thể.
ORDER BY varchar_column::int
Đảm bảo có các ký tự số nguyên hợp lệ trong varchar
của bạn cho mỗi mục nhập hoặc bạn nhận được một ngoại lệ invalid input syntax for integer: ...
. (Khoảng trắng ở đầu và cuối là ok - nó sẽ được cắt tự động.)
Tuy nhiên, nếu đúng như vậy thì tại sao không chuyển đổi cột thành integer
đầu tiên là? Nhỏ hơn, nhanh hơn, sạch hơn, đơn giản hơn.
Làm cách nào để tránh các trường hợp ngoại lệ?
Để xóa các ký tự không phải chữ số trước khi truyền và do đó tránh các ngoại lệ có thể xảy ra:
ORDER BY NULLIF(regexp_replace(varchar_column, '\D', '', 'g'), '')::int
-
regexp_replace()
biểu thức loại bỏ hiệu quả tất cả các không phải chữ số, do đó chỉ còn lại các chữ số hoặc một chuỗi trống. (Xem bên dưới.) -
\D
là viết tắt của lớp ký tự[^[:digit:]]
, nghĩa là tất cả không phải chữ số ([^0-9]
).
Trong các phiên bản Postgres cũ với cài đặt lỗi thờistandard_conforming_strings = off
, bạn phải sử dụng cú pháp chuỗi thoát PosixE'\\D'
để thoát khỏi dấu gạch chéo ngược\
. Điều này là mặc định trong Postgres 8.3, vì vậy bạn sẽ cần nó cho phiên bản lỗi thời của mình. -
Tham số thứ 4
g
dành cho "toàn cầu" , hướng dẫn thay thế tất cả lần xuất hiện, không chỉ lần đầu tiên. -
Bạn có thể muốn cho phép một dấu gạch ngang ở đầu (
-
) cho các số âm. -
Nếu chuỗi không có chữ số nào, kết quả là một chuỗi trống không hợp lệ để truyền thành
integer
. Chuyển đổi chuỗi trống thànhNULL
vớiNULLIF
. (Bạn có thể xem xét0
thay vào đó.)
Kết quả được đảm bảo là hợp lệ. Quy trình này dành cho truyền thành integer
như được yêu cầu trong phần nội dung câu hỏi, không dành cho numeric
như tiêu đề đã đề cập.
Làm thế nào để làm cho nó nhanh chóng?
Một cách là chỉ mục trên một biểu thức.
CREATE INDEX tbl_varchar_col2int_idx ON tbl
(cast(NULLIF(regexp_replace(varchar_column, '\D', '', 'g'), '') AS integer));
Sau đó, sử dụng cùng một biểu thức trong ORDER BY
mệnh đề:
ORDER BY
cast(NULLIF(regexp_replace(varchar_column, '\D', '', 'g'), '') AS integer)
Kiểm tra với EXPLAIN ANALYZE
liệu chỉ mục chức năng có thực sự được sử dụng hay không.