2015-10-13 16 views
5

Làm cách nào để thực thi một bảng chỉ có một hàng? Dưới đây là những gì tôi đã thử. Kích hoạt UPDATE có thể hoạt động, tuy nhiên, kích hoạt CREATE chắc chắn sẽ không hoạt động. Đối với CREATE, tôi muốn sử dụng SET, tuy nhiên, SET không được hỗ trợ bởi SQLite.Đảm bảo bảng SQLite chỉ có một hàng

CREATE TABLE IF NOT EXISTS `config` (
    `id` TINYINT NOT NULL DEFAULT 0, 
    `subdomain` VARCHAR(45) NOT NULL, 
    `timezone` CHAR(3) NOT NULL, 
    `timeout` TINYINT NOT NULL, 
    `offline` TINYINT NOT NULL, 
    `hash_config` CHAR(32) NOT NULL, 
    `hash_points` CHAR(32) NOT NULL, 
    PRIMARY KEY (`id`)); 

INSERT INTO config(id,subdomain,timezone,timeout,offline,hash_config,hash_points) VALUES(0,'subdomain','UTC',5,0,'hash_config','hash_points'); 

CREATE TRIGGER `config_insert_zero` 
BEFORE INSERT ON `config` 
FOR EACH ROW 
BEGIN 
    -- SET NEW.id=0; 
    NEW.id=OLD.id; 
END; 

CREATE TRIGGER `config_update_zero` 
BEFORE UPDATE ON `config` 
FOR EACH ROW 
BEGIN 
    -- SET NEW.id=0; 
    NEW.id=OLD.id; 
END; 

Trả lời

7

Trong trường hợp chung, để giới hạn số hàng trong bảng, bạn phải ngăn chặn thêm bất kỳ chèn nào. Trong SQLite, điều này được thực hiện với RAISE():

CREATE TRIGGER config_no_insert 
BEFORE INSERT ON config 
WHEN (SELECT COUNT(*) FROM config) >= 1 -- limit here 
BEGIN 
    SELECT RAISE(FAIL, 'only one row!'); 
END; 

Tuy nhiên, nếu quá giới hạn là một trong, bạn có thể thay vì chỉ đơn giản là hạn chế khóa chính đến một giá trị cố định:

CREATE TABLE config (
    id INTEGER PRIMARY KEY CHECK (id = 0), 
    [...] 
); 
+0

Tôi thích giải pháp thứ hai của bạn! Cảm ơn lời giải thích về 'RAISE'. Không phải là tôi sẽ cần phải sử dụng một kích hoạt cho giải pháp thứ hai của bạn, làm thế nào để hạn chế 'UPDATE' được thực thi? Cách tôi hiển thị nó bằng cách sử dụng 'CREATE TRIGGER config_update_zero TRƯỚC KHI CẬP NHẬT VỀ cấu hình CHO MACHI ROW BEGIN NEW.id = OLD.id; END; NEW.id = OLD.id; '? – user1032531

+0

Bạn cần kích hoạt UPDATE để làm gì? –

+0

Không muốn cho phép 'UPDATE config SET id = 2'. Cấp, giải pháp thứ hai của bạn ngăn chặn điều này, và chỉ tò mò làm thế nào nó sẽ được thực hiện với một kích hoạt. – user1032531

1

Một ý tưởng bạn có thể muốn để xem xét là làm cho nó xuất hiện như bảng chỉ có một hàng. Trong thực tế, bạn giữ tất cả các hàng trước đó bởi vì nó hoàn toàn có thể bạn sẽ một ngày nào đó muốn duy trì một lịch sử của tất cả các giá trị trong quá khứ.

Vì chỉ có một hàng, thực sự không cần cột ID, mục đích của nó là phân biệt duy nhất mỗi hàng từ tất cả các cột khác. Tuy nhiên, bạn cần một dấu thời gian sẽ được sử dụng để xác định "một hàng" sẽ là hàng mới nhất được ghi vào bảng.

CREATE TABLE `config_history` (
    `created` timestamp default current_timestamp, 
    `subdomain` VARCHAR(45) NOT NULL, 
    `timezone` CHAR(3) NOT NULL, 
    `timeout` TINYINT NOT NULL, 
    `offline` TINYINT NOT NULL, 
    `hash_config` CHAR(32) NOT NULL, 
    `hash_points` CHAR(32) NOT NULL, 
    PRIMARY KEY (`created`) 
); 

Vì bạn thường quan tâm đến việc chỉ hàng cuối cùng bằng văn bản (phiên bản mới nhất), truy vấn chọn hàng với ngày tạo mới nhất:

select ch.created effective_date, ch.subdomain, ch.timezone, ch.timeout, 
     ch.offline, ch.hash_config, ch.hash_points 
from config_history ch 
where ch.created =(
     select max(created) 
     from config_history); 

Đặt một create view config as trước truy vấn này và bạn có chế độ xem chỉ chọn một hàng, mới nhất, từ bảng. Bất kỳ truy vấn đối với quan điểm trả về một hàng:

select * 
from config; 

Một instead of kích hoạt trên quan điểm có thể chuyển đổi cập nhật cho Chèn - bạn không thực sự muốn thay đổi một giá trị, chỉ cần viết một dòng mới với các giá trị mới . Điều này sau đó trở thành hàng "hiện tại" mới.

Bây giờ bạn có những gì dường như là một bảng chỉ có một hàng nhưng bạn cũng duy trì một lịch sử đầy đủ của tất cả các thay đổi trong quá khứ từng được thực hiện cho hàng đó.

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