如何强制表只有一行?以下是我的尝试。 UPDATE
触发器可能有效,但CREATE
触发器肯定不会。对于CREATE,我想使用SET
,但SQLite不支持SET
。
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;
答案 0 :(得分:17)
在一般情况下,要限制表中的行数,必须阻止任何进一步的插入。 在SQLite中,这是通过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;
但是,如果限制为1,则可以简单地将主键限制为固定值:
CREATE TABLE config (
id INTEGER PRIMARY KEY CHECK (id = 0),
[...]
);
答案 1 :(得分:5)
您可能想要考虑的一个想法是让它看起来像表只有一行。实际上,您保留以前的所有行,因为很可能您有一天会想要保留所有过去值的历史记录。
由于只有一行,所以实际上不需要ID列,其目的是唯一地区分每一行和所有其他行。但是,您确实需要一个时间戳,用于标识"一行"这将是写入表格的最新一行。
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`)
);
由于您通常只对最后一行(最新版本)感兴趣,因此查询会选择具有最新创建日期的行:
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 );
在此查询前放置create view config as
,您有一个视图,只从表中选择一行,即最新的一行。对视图的任何查询都会返回一行:
select *
from config;
视图上的instead of
触发器可以将更新转换为插入 - 您实际上并不想更改值,只需使用新值写入新行。然后它成为新的"当前"行。
现在您看起来只有一行的表格,但您也保留了以前对该行所做的所有过去更改的完整历史记录。