2013-05-06 23 views
10

Tôi đang cố gắng tạo chỉ mục trên diễn viên của một cột VARCHAR cho đến nay. Tôi đang làm một cái gì đó như thế này:PostgreSQL tạo chỉ mục trên diễn viên từ chuỗi đến ngày

CREATE INDEX date_index ON table_name (CAST(varchar_column AS DATE)); 

Tôi nhận được lỗi: functions in index expression must be marked IMMUTABLE Nhưng tôi không hiểu tại sao, các diễn viên cho đến nay không phụ thuộc vào múi giờ hoặc một cái gì đó như thế (mà làm cho một cast vào dấu thời gian với múi giờ cho lỗi này).

Bất kỳ trợ giúp nào?

+0

Có cách nào để chuyển đổi ngày qua một quy tắc định dạng cụ thể không? SQL Server không muốn thực hiện các chuyển đổi như vậy nếu định dạng phải được đoán. – user2246674

Trả lời

10

Lỗi đầu tiên của bạn là lưu trữ ngày dưới dạng cột VARCHAR. Bạn không nên làm điều đó.

Sửa lỗi thích hợp cho sự cố của bạn là chuyển cột thành cột date thực.

Bây giờ tôi khá chắc chắn câu trả lời cho tuyên bố đó là "Tôi không thiết kế cơ sở dữ liệu và tôi không thể thay đổi nó", vì vậy đây là một cách giải quyết:

CASTto_char() không bất biến vì họ có thể trả về các giá trị khác nhau cho cùng một giá trị đầu vào tùy thuộc vào cài đặt của phiên hiện tại.

Nếu bạn biết bạn có định dạng nhất quán của tất cả các giá trị trong bảng (nếu bạn có - nghĩa là bạn có thể chuyển cột thành cột date thực) thì bạn có thể tạo hàm của riêng mình để chuyển đổi một varchar thành một ngày và được đánh dấu là không thay đổi.

create or replace function fix_bad_datatype(the_date varchar) 
    returns date 
    language sql 
    immutable 
as 
$body$ 
    select to_date(the_date, 'yyyy-mm-dd'); 
$body$ 
ROWS 1 
/

Với định nghĩa rằng bạn có thể tạo một chỉ mục trên các biểu hiện:

CREATE INDEX date_index ON table_name (fix_bad_datatype(varchar_column)); 

Nhưng bạn để sử dụng một cách chính xác rằng chức năng cuộc gọi trong truy vấn của bạn để Postgres sử dụng nó:

select * 
from foo 
where fix_bad_datatype(varchar_column) < current_date; 

Lưu ý rằng cách tiếp cận này sẽ không thành công nếu bạn chỉ có một giá trị "bất hợp pháp" trong cột VARCHAR của bạn. Giải pháp hợp lý duy nhất để lưu trữ ngày là date s,

+2

@Topo: 'to_date()' cũng chỉ là 'STABLE', không phải' IMMUTABLE', mặc dù điều này có thể tốt. [Ở đây] (http://www.postgresql.org/message-id/flat/[email protected]#[email protected]) là một cuộc thảo luận về danh sách devel là lý do tại sao. –

+0

Nhưng khi tôi sử dụng một truy vấn như thế này 'chọn * từ foo nơi fix_bad_datatype (varchar_column)> = '2015-02-05' :: date;' mà không sử dụng 'current_date' phải mất nhiều thời gian hơn so với thực thi nó mà không có chỉ mục. Bất kỳ ý tưởng? –

+0

@MarlonAbeykoon: https://wiki.postgresql.org/wiki/Slow_Query_Questions –

2

Vui lòng cung cấp phiên bản cơ sở dữ liệu, bảng ddl và một số dữ liệu mẫu.

Làm cho chức năng bất biến của riêng bạn làm những gì bạn muốn, như thế này? Ngoài ra, hãy xem xét việc tạo một dàn diễn viên mới trong tài liệu và xem điều đó có làm gì cho bạn hay không.

create table emp2 (emp2_id integer, hire_date VARCHAR(100)); 

insert into emp2(hire_date) 
select now(); 

select cast(hire_date as DATE) 
from emp2 


CREATE FUNCTION my_date_cast(VARCHAR) RETURNS DATE 
    AS 'select cast($1 as DATE)' 
    LANGUAGE SQL 
    IMMUTABLE 
    RETURNS NULL ON NULL INPUT; 


CREATE INDEX idx_emp2_hire_date ON emp2 (my_date_cast(hire_date)); 
+0

Và làm cách nào để chúng tôi truy vấn trên chỉ mục riêng biệt? – Chris

Các vấn đề liên quan