2010-01-08 18 views
8

Tôi đang tái cấu trúc quy trình nhập dữ liệu cho một ứng dụng doanh nghiệp và bắt gặp một đoạn trích tôi muốn tìm một giải pháp tốt hơn. Khi nhập dữ liệu, chúng ta phải tạo một thực thể duy nhất cho mỗi tập dữ liệu và có một bộ đếm trong một trường được sử dụng để gán id này tuần tự. Bạn đọc lĩnh vực này để có được id miễn phí tiếp theo và tăng nó sau đó để chuẩn bị cho lần sau.Oracle SQL: Cách đọc và gia tăng trường

Tại thời điểm này được thực hiện theo hai bước trong ứng dụng ban đầu, được viết trong 'C':

SELECT idnext FROM mytable; 
    UPDATE mytable SET idnext = idnext + 1; 

Rõ ràng có một điều kiện chủng tộc ở đây, nếu nhiều quá trình làm điều tương tự.

Chỉnh sửa: Điều quan trọng cốt lõi: Tôi không thể chạm vào định nghĩa cơ sở dữ liệu/trường, quy tắc này ra một chuỗi.

Chúng tôi đang viết lại trong perl và tôi muốn làm điều tương tự, nhưng tốt hơn. Một giải pháp nguyên tử sẽ tốt đẹp. Rất tiếc, các kỹ năng SQL của tôi bị giới hạn, vì vậy tôi chuyển sang trí tuệ tập thể :-)

+0

Tôi cảm thấy sql cập nhật chỉ đủ đúng 'CẬP NHẬT mytable SET idnext = idnext + 1;' tại sao bạn cần phải đọc idnext đến máy chủ? –

Trả lời

9

Trong trường hợp cụ thể này, một chuỗi là giải pháp đúng như đã đề cập. Nhưng nếu trong một số tình huống trong tương lai bạn cần phải cập nhật cả một cái gì đó và trả về một giá trị trong báo cáo kết quả tương tự, bạn có thể sử dụng RETURNING khoản:

UPDATE atable SET foo = do_something_with(foo) RETURNING foo INTO ? 

Nếu mã gọi là PL/SQL, thay thế? với biến PL/SQL cục bộ; nếu không bạn có thể ràng buộc nó như là một tham số đầu ra trong chương trình của bạn.

Chỉnh sửa: Kể từ khi bạn đề cập đến Perl, một cái gì đó như thế này nên làm việc (chưa được kiểm tra):

my $sth = $dbh->prepare('UPDATE mytable SET idnext = idnext + 1 returning idnext into ?'); 
my $idnext; 
$sth->bind_param_inout(1, \$idnext, 8); 
$sth->execute; # now $idnext should contain the value 

Xem DBI.

+0

Vì vậy, tuyên bố của tôi sẽ giống như thế này: (?) CẬP NHẬT mytable SET idnext = idnext + 1 RETURNING idnext; –

+0

Mã gọi của tôi là perl. Tôi đã thử điều này trên dòng lệnh sql, nhưng nó có vấn đề cú pháp: CẬP NHẬT mytable SET idnext = idnext + 1 RETURNING idnext –

+0

phần INTO là bắt buộc. Và nó sẽ không hoạt động trên một dòng lệnh (theo như tôi biết). – Dan

4

Tại sao không sử dụng sequence?

Tạo chuỗi một lần, sử dụng bất cứ điều gì bắt đầu với giá trị mà bạn muốn:

CREATE SEQUENCE mysequence 
    START WITH 1 
    MAXVALUE 999999999999999999999999999 
    MINVALUE 1 
    NOCYCLE 
    NOCACHE 
    NOORDER; 

Sau đó, trong mã ứng dụng của bạn trong thời gian chạy, bạn có thể sử dụng báo cáo này để có được những giá trị tiếp theo:

SELECT mysequence.NEXTVAL 
    INTO idnext 
    FROM DUAL; 

Cập nhật: Sử dụng trình tự sẽ là phương pháp ưu tiên, nhưng vì bạn không thể thay đổi cơ sở dữ liệu nên tôi đồng ý rằng việc sử dụng RETURNING sẽ hoạt động cho trường hợp của bạn:

UPDATE mytable 
     SET idnext = idnext + 1 
RETURNING idnext 
    INTO mylocalvariable; 
+0

Tôi phải sử dụng trường hiện có và không thể chạm vào định nghĩa của nó. –

2

Sử dụng câu lệnh SELECT FOR UPDATE. Nó đảm bảo quyền loại trừ lẫn nhau để kỷ lục:

"SELECT FOR UPDATE;

+0

Bạn có thể cung cấp một ví dụ đầy đủ không? –

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