2012-03-26 41 views
11

Tôi hiện đang cố gắng tạo cơ sở dữ liệu sqlite nơi tôi có thể nhập bảng từ cơ sở dữ liệu sqlite khác (không thể đính kèm) và thêm một số dữ liệu bổ sung vào mỗi cột.INSERT HOẶC THAY THẾ + khoá ngoại ON DELETE CASCADE làm việc quá tốt

vì không có INSERT OR UPDATE tôi đến với điều này:
Tôi đã suy nghĩ về việc tách các dữ liệu vào hai bảng và tham gia cùng họ sau đó vì vậy tôi chỉ có thể đổ toàn bộ nhập khẩu vào một bảng thay thế tất cả những gì đã thay đổi và quản lý thêm dữ liệu riêng biệt vì điều đó không thay đổi khi nhập.

Các bảng đầu tiên (chúng ta hãy gọi nó base_data) sẽ trông như thế

local_id | remote_id | base_data1 | base_data2 | ... 
---------+-----------+------------+------------+---- 

bên cạnh những local_id tất cả mọi thứ sẽ chỉ được một tấm gương của cơ sở dữ liệu từ xa (tôi có lẽ sẽ thêm một dấu thời gian đồng bộ nhưng điều đó không thành vấn đề hiện nay).

Bảng thứ hai sẽ trông tương tự nhưng có remote_id bộ như nước ngoài chủ chốt

remote_id | extra_data1 | extra_data2 | ... 
----------+-------------+-------------+---- 

    CREATE TABLE extra_data (
     remote_id INTEGER 
      REFERENCES base_data(remote_id) 
      ON DELETE CASCADE ON UPDATE CASCADE 
      DEFERRABLE INITIALLY DEFERRED, 
     extra_data1 TEXT, 
     extra_data2 TEXT, 
     /* etc */ 
    ) 

Bây giờ ý tưởng của tôi là chỉ đơn giản là INSERT OR REPLACE INTO base_data ... giá trị vì cơ sở dữ liệu tôi nhập khẩu từ không có dấu thời gian đồng bộ hoặc bất cứ điều gì và tôi sẽ phải so sánh tất cả mọi thứ để tìm ra những gì hàng tôi phải UPDATE/những gì để INSERT.

Nhưng ở đây nằm vấn đề: INSERT OR REPLACE thực sự là một DELETE tiếp theo là một INSERT và phần xóa kích hoạt ngoại khóa ON DELETE mà tôi nghĩ tôi có thể ngăn ngừa bằng cách làm cho chế DEFERRED. Nó không hoạt động nếu tôi quấn INSERT OR REPLACE trong một giao dịch. Nó luôn xóa dữ liệu phụ của tôi mặc dù cùng một khóa ngoại tồn tại sau câu lệnh.

Có thể dừng ON DELETE để kích hoạt cho đến khi INSERT OR REPLACE kết thúc? Có lẽ một số chế độ giao dịch đặc biệt/pragma?

Trả lời

3

Có vẻ như công việc nếu tôi thay thế các phần ON DELETE CASCADE bởi một nút bấm như:

CREATE TRIGGER on_delete_trigger 
    AFTER DELETE ON base_data 
    BEGIN 
     DELETE FROM extra_data WHERE extra_data.remote_id=OLD.remote_id; 
    END; 

kích hoạt Đó là chỉ kích hoạt bởi một tuyên bố DELETE và nên giải quyết vấn đề của tôi cho đến nay.

(trả lời được cung cấp bởi các OP trong câu hỏi)

thông tin bổ sung bởi jmathew, trích dẫn các documentation:

Khi chiến lược giải quyết REPLACE xung đột xóa hàng để đáp ứng một hạn chế, các trình kích hoạt xóa sẽ kích hoạt nếu và chỉ khi các trình kích hoạt đệ quy được bật.

0

Giả sử bạn chỉ có một mối quan hệ khóa ngoại trên một khóa chính trong bảng tham chiếu của bạn (như bạn làm trong ví dụ của bạn), đây là một giải pháp khá khó chịu đối với tôi.

Chỉ cần tắt kiểm tra khóa ngoài, chạy truy vấn thay thế, sau đó bật lại khóa ngoại.

Nếu truy vấn thay thế là truy vấn duy nhất chạy trong khi khóa ngoại bị tắt, bạn có thể yên tâm rằng không có khóa ngoại nào bị xử lý. Nếu bạn đang chèn một hàng mới, sẽ không có cơ hội nào được liên kết với nó và nếu bạn đang thay thế hàng, hàng hiện tại sẽ không bị xóa hoặc khóa chính bị truy vấn thay đổi do đó ràng buộc sẽ vẫn giữ khi các khóa ngoại được kích hoạt lại.

Mã SQLlite trông giống như sau:

PRAGMA foreign_keys=OFF; 
INSERT OR REPLACE ...; 
PRAGMA foreign_keys=ON; 
Các vấn đề liên quan