2010-02-24 29 views
11

Tôi có một truy vấn tham gia hai bảng. Một bảng có một cột thuộc loại varchar và bảng kia có loại số. Tôi đã thực hiện truy vấn của tôi trên 3 cơ sở dữ liệu oracle, và đang thấy một số kết quả lạ tôi hy vọng có thể được giải thích. Trên hai cơ sở dữ liệu giống như các công trình sau đây.Số Oracle và tham số varchar

select a.col1, b.somecol 
from tableA a inner join tableB b on b.col2=a.col1; 

Trong bảng truy vấn nàyA.col1 là loại số và tableB.col2 thuộc loại varchar. Điều này làm việc tốt trong hai cơ sở dữ liệu nhưng không hoạt động trong cơ sở dữ liệu thứ ba. Trong lần thứ ba tôi nhận được (ORA-01722) lỗi. Trong lần thứ ba, tôi cần phải làm một cái gì đó như ...

select a.col1, b.somecol 
from tableA a inner join tableB b on b.col2=to_char(a.col1); 

Điều này làm việc trong tất cả các cơ sở dữ liệu. Câu hỏi tôi có là tại sao? Ở trên là một truy vấn được đơn giản hóa và truy vấn thực sự phức tạp hơn một chút và truy xuất rất nhiều dữ liệu, do đó phiên bản đầu tiên nhanh hơn nhiều. Nếu tôi có thể làm điều đó để làm việc trong mọi môi trường thì nó sẽ rất tuyệt.

Có ai biết lý do tại sao điều này có thể hoạt động trong một số cơ sở dữ liệu oracle và không phải những người khác không có dàn diễn viên trên kiểu dữ liệu? Có một cài đặt chung cho phép hành vi như vậy không?

+1

Collation sẽ đoán đầu tiên của tôi. Oracle thường cho phép chuyển đổi ngầm, vì vậy có thể là một cột không chuyển đổi ẩn ... –

+1

Bạn đã viết tất cả những từ đó và bạn vẫn không giải thích được chính xác * cách * truy vấn đầu tiên không hoạt động trong cơ sở dữ liệu thứ ba. – APC

+0

Xin lỗi, tôi nhận được lỗi ORA-01722 trong truy vấn đầu tiên, cơ sở dữ liệu thứ ba – broschb

Trả lời

15

Một lý do tại sao chuyển đổi tiềm ẩn không thành công là khi cột varchar tham gia chứa dữ liệu không phải là số. Oracle xử lý số để varchar2 tham gia bằng cách chuyển đổi chuỗi (xem trích dẫn của Gary trong bình luận của ông), vì vậy nó thực sự thực hiện điều này:

select a.col1, b.somecol 
from tableA a inner join tableB b on to_number(b.col2)=a.col1; 

Nếu tableB.col2 chứa các giá trị mà không phải là số - dường như rất có thể, nó là một chuỗi sau khi tất cả - sau đó nó sẽ ném ORA-01722: invalid number. Bằng cách đúc một cách rõ ràng cột số thành một chuỗi, bạn sẽ cắt ngắn hành vi mặc định của Oracle.

Thực tế là bạn không gặp vấn đề này trong hai môi trường đầu tiên của bạn là một vấn đề không may mắn khi cấu hình. Nó có thể tấn công bất cứ lúc nào, bởi vì nó chỉ yêu cầu một chuỗi không phải là số để phá vỡ truy vấn. Vì vậy, thực sự bạn nên chạy với chuyển đổi rõ ràng trong tất cả các môi trường.

Đối với hiệu suất, bạn có thể xây dựng một chỉ số dựa trên chức năng ...

create index whatever_idx on tableA (to_char(col1)) 
/
+2

Một chút sau http://download.oracle.com/docs/cd/B19306_01/server.102/b14200 /sql_elements002.htm#r16c1-t41 "Khi so sánh một giá trị ký tự với một giá trị số, Oracle chuyển đổi dữ liệu ký tự thành một giá trị số." –

+0

Bạn có thể truyền số trong bảngA thành một chuỗi thay vì vậy bạn sẽ không gặp lỗi nếu có một chuỗi không phải là số trong bảngB. tức là CAST (a.col1 AS VARCHAR (20)) –