Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ensure SQLite table only has one row

Tags:

sql

sqlite

How can I enforce a table to have only one row? Below is what I tried. The UPDATE trigger might work, however, the CREATE trigger definitely will not. For the CREATE, I would like to use SET, however, SET is not supported by SQLite.

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;
like image 945
user1032531 Avatar asked Oct 13 '15 13:10

user1032531


People also ask

How do I limit the number of rows in SQLite?

SQLite Limit: You can limit the number of rows returned by your SQL query, by using the LIMIT clause. For example, LIMIT 10 will give you only 10 rows and ignore all the other rows. In the LIMIT clause, you can select a specific number of rows starting from a specific position using the OFFSET clause.

Does except work in SQLite?

The EXCEPT operator returns all records from the first SELECT statement that are not in the second SELECT statement. The EXCEPT operator in SQLite is equivalent to the MINUS operator in Oracle.

How do I find the number of rows in SQLite?

In SQLite the Count(*) function will return total number of rows available in a table, including the rows which contain NULL values. The Count(*) will not take any parameters other than the asterisk symbol (*).

Does SQLite support Autoincrement?

SQLite AUTOINCREMENT is a keyword used for auto incrementing a value of a field in the table. We can auto increment a field value by using AUTOINCREMENT keyword when creating a table with specific column name to auto increment.


2 Answers

In the general case, to limit the number of rows in a table, you have to prevent any further insert. In SQLite, this is done with 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;

However, if the limit is one, you could instead simply constrain the primary key to a fixed value:

CREATE TABLE config (
    id INTEGER PRIMARY KEY CHECK (id = 0),
    [...]
);
like image 106
CL. Avatar answered Oct 13 '22 03:10

CL.


One idea you may want to consider is to make it appear like the table has only one row. In reality, you keep all previous rows because it's quite possible you will one day want to maintain a history of all past values.

Since there is only one row, there really is no need for an ID column, the purpose of which is to uniquely differentiate each row from all the others. You do need, however, a timestamp which will be used to identify the "one row" which will be the latest row written to the table.

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`)
);

Since you are normally interested in only the last row written (the latest version), the query selects the row with the latest creation date:

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 );

Put a create view config as in front of this query and you have a view that selects only one row, the latest, from the table. Any query against the view returns the one row:

select  *
from    config;

An instead of trigger on the view can convert Updates to Inserts -- you don't actually want to change a value, just write a new row with the new values. This then becomes the new "current" row.

Now you have what appears to be a table with only one row but you also maintain a complete history of all the past changes ever made to that row.

like image 27
TommCatt Avatar answered Oct 13 '22 05:10

TommCatt