Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add constraint to existing SQLite table

I'm using SQLite, which doesn't support adding a constraint to an existing table.

So I can't do something like this (just as an example):

ALTER TABLE [Customer]
ADD CONSTRAINT specify_either_phone_or_email
CHECK (([Phone] IS NOT NULL) OR ([Email] IS NOT NULL));

Are there any workarounds for this scenario?

I know:

  • I can add a constraint for a new table, but it isn't new (and it's generated by my ORM, EF Core)
  • I can do a "table rebuild" (rename table, create new one, copy old data, drop temp table) but that seems really complex

Ideas

  • Can I somehow make a copy of the table into a new table, with some schema changes?
  • Or "get" the schema somehow, and edit it in a SQL script, then add a table with that schema?
like image 1000
grokky Avatar asked Mar 23 '17 06:03

grokky


People also ask

How can you add constraints to an existing table?

The basic syntax of an ALTER TABLE command to add a NOT NULL constraint to a column in a table is as follows. ALTER TABLE table_name MODIFY column_name datatype NOT NULL; The basic syntax of ALTER TABLE to ADD UNIQUE CONSTRAINT to a table is as follows.

How do I add a foreign key to an existing table in SQLite?

How to Add a Foreign Key to an Existing Table. You can not use the ALTER TABLE statement to add a foreign key in SQLite. Instead you will need to rename the table, create a new table with the foreign key, and then copy the data into the new table.

How do I edit a table in SQLite?

Summary. Use the ALTER TABLE statement to modify the structure of an existing table. Use ALTER TABLE table_name RENAME TO new_name statement to rename a table. Use ALTER TABLE table_name ADD COLUMN column_definition statement to add a column to a table.

How do I add constraints to an existing table in MySQL?

The syntax for creating a unique constraint using an ALTER TABLE statement in MySQL is: ALTER TABLE table_name ADD CONSTRAINT constraint_name UNIQUE (column1, column2, ... column_n); table_name.


1 Answers

To make a copy of a table with some schema changes, you have to do the creation and the copying manually:

BEGIN;
CREATE TABLE Customer_new (
    [...],
    CHECK ([...])
);
INSERT INTO Customer_new SELECT * FROM Customer;
DROP TABLE Customer;
ALTER TABLE Customer_new RENAME TO Customer;
COMMIT;

To read the schema, execute .schema Customer in the sqlite3 command-line shell. This gives you the CREATE TABLE statement, which you can edit and execute.


To change the table in place, you can use a backdoor.

First, read the actual table definition (this is the same as what you would get from .schema):

SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'Customer';

Add your CHECK constraint to that string, then enable write access to sqlite_master with PRAGMA writable_schema=1; and write your new table definition into it:

UPDATE sqlite_master SET sql='...' WHERE type='table' AND name='Customer';

Then reopen the database.

WARNING: This works only for changes that do not change the on-disk format of the table. If you do make any change that changes the record format (such as adding/removing fields, or modifying the rowid, or adding a constraint that needs an internal index), your database will blow up horribly.

like image 170
CL. Avatar answered Sep 18 '22 16:09

CL.