2010-11-01 51 views
17

Vì vậy, tôi đã cố gắng giải quyết vấn đề này nhưng có vẻ như dòng cuối cùng (kiểm tra) không cho phép truy vấn phụ trong đó. Bất kỳ cách nào để làm cho công việc này Oracle?Sử dụng truy vấn con trong câu lệnh Kiểm tra trong Oracle

CREATE TABLE Tank (
    n_id   int, 
    day    date, 
    level   int, 
    CONSTRAINT pk_w_td PRIMARY KEY (n_id,day), 
    CONSTRAINT fk_w_td_tan FOREIGN KEY (n_id) REFERENCES Tanks ON DELETE CASCADE, 
    CHECK (level > 0 AND level <= (SELECT capacity FROM Tanks WHERE Tanks.n_id = TanksDay.n_id)) 
); 

Dưới đây là các thông tin lỗi:

Error at Command Line:7 Column:32 Error report: SQL Error: ORA-02251: subquery not allowed here 
02251. 00000 - "subquery not allowed here" 
*Cause: Subquery is not allowed here in the statement. 
*Action: Remove the subquery from the statement. 
+1

Câu hỏi hay. Các ràng buộc chung của bảng chéo (ngoài các ràng buộc FK) là một trong những tính năng tôi muốn thấy nhất được thêm vào Oracle. –

Trả lời

22

Có ba cách cơ bản để giải quyết loại sự cố này vì ràng buộc CHECK không thể dựa trên truy vấn.

Lựa chọn 1: Kích hoạt

Phương pháp đơn giản nhất là nên đặt một kích hoạt trên TANK rằng truy vấn TANKS và ném một ngoại lệ nếu CẤP vượt quá năng lực. Tuy nhiên, vấn đề với kiểu tiếp cận đơn giản này là gần như không thể xử lý các vấn đề tương tranh một cách chính xác. Nếu phiên 1 giảm CAPACITY, thì phiên 2 tăng LEVEL, và sau đó cả hai giao dịch cam kết, trình kích hoạt sẽ không thể phát hiện vi phạm. Đây có thể không phải là một vấn đề nếu một hoặc cả hai bảng hiếm khi được sửa đổi, nhưng nói chung nó sẽ là một vấn đề.

Phương án 2: quan điểm vật hoá

Bạn có thể giải quyết vấn đề đồng thời bằng cách tạo ra một tín hiệu ON COMMIT cụ thể hóa quan điểm cho rằng gia nhập TANK và TANKS bảng và sau đó tạo ra một hạn chế CHECK trên quan điểm cụ thể hóa để xác nhận rằng CẤP < = CAPACITY. Bạn cũng có thể tránh lưu trữ dữ liệu hai lần bằng cách xem materialized chỉ chứa dữ liệu có thể vi phạm ràng buộc. Điều này sẽ yêu cầu các bản ghi xem vật hoá trên cả hai bảng cơ sở sẽ bổ sung thêm một chút chi phí để chèn (mặc dù ít hơn sử dụng trình kích hoạt). Việc đẩy kiểm tra đến cam kết-thời gian sẽ giải quyết vấn đề đồng thời nhưng nó giới thiệu một chút của một vấn đề quản lý ngoại lệ vì thao tác COMMIT có thể không thành công vì việc làm mới chế độ xem được thực hiện không thành công. Ứng dụng của bạn sẽ cần có khả năng xử lý vấn đề đó và để cảnh báo người dùng về thực tế đó.

Lựa chọn 3: Thay đổi mô hình dữ liệu

Nếu bạn có một giá trị trong bảng A mà phụ thuộc vào giới hạn trong bảng B, mà có thể chỉ ra rằng giới hạn trong B nên được một thuộc tính của bảng A (thay vì hoặc ngoài việc là thuộc tính của bảng B). Nó phụ thuộc vào các chi tiết cụ thể của mô hình dữ liệu của bạn, tất nhiên, nhưng nó thường đáng xem xét.

7

Không may KIỂM TRA trở ngại không thể chứa các truy vấn con - xem documentation.

0

Có thể bạn sẽ cần tạo trình kích hoạt và sử dụng RAISE_APPLICATION_ERROR nếu nó nằm ngoài phạm vi cho phép.

+0

Và một điều khác cần cân nhắc khi tạo trình kích hoạt, bạn có thể muốn kích hoạt trên khả năng giữ bảng để đảm bảo rằng nó không bao giờ được làm nhỏ hơn mức tối đa. –

1

Câu trả lời của Justin có một số ý tưởng hay. Một cách khác là bọc tất cả các chèn/cập nhật vào bảng bằng một gói (một TAPI, nếu bạn muốn), và thực hiện kiểm tra ở đó. Bạn sẽ cần phải đảm bảo rằng tất cả các ứng dụng đều sử dụng TAPI của bạn. Bạn cũng sẽ cần triển khai một số khóa tùy chỉnh để bảo vệ ràng buộc khỏi các tác động của hoạt động đồng thời.

1

Tính năng bạn đang tìm kiếm được gọi là xác nhận SQL, and it's not yet implemented in Oracle 12c

+0

Tôi đồng ý, xác nhận có thể giải quyết loại nhu cầu này một cách hoàn hảo. –

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