Возможно ли принудительно применять типы данных SQLite?

#sqlite

#sqlite

Вопрос:

Насколько я понимаю, тип данных sqlite связан не с его столбцом, а с самими данными: это практически означает, что вы можете вставлять любые данные в любой столбец.

Возможно ли запретить такое поведение? Я имею в виду, я хочу, чтобы sqlite выдавал ошибку (или, по крайней мере, предупреждение), когда я случайно пытаюсь вставить текст в целое число, например.

Комментарии:

1. Звучит не так… sqlite.org/faq.html#q3

Ответ №1:

Вы можете использовать ограничения ПРОВЕРКИ и typeof() для проверки фактического типа данных:

 CREATE TABLE MyTable (
    Col1 INTEGER  CHECK (typeof(Col1) = 'integer'),
    Col2 TEXT     CHECK (typeof(Col2) IN ('text', 'null')
);
  

Ответ №2:

Я полагаю, вы могли бы использовать CHECK ограничение, например

 CREATE TABLE testinsert (
    COL1 INTEGER, 
    COL2 INTEGER CHECK (CAST(COL2||1 AS INTEGER) <> 0) -- column constraint
    CHECK (CAST(COL1||1 AS INTEGER) <> 0) -- table constraint
);
  
  • это создает таблицу с двумя столбцами COL1 и COL2.
  • оба столбца имеют одинаковое ограничение, но применяются к столбцам по-разному

    • В COL1 ограничение ПРОВЕРКИ применено как ограничение таблицы
    • В COL2 ограничение ПРОВЕРКИ применяется как ограничение столбца
  • Ограничение работает путем проверки значения столбца при ПРИВЕДЕНИИ к ЦЕЛОМУ числу. Результатом будет 0 (false), если значение не является целым числом. Однако, чтобы использовать 0 в качестве допустимого значения, 1 объединяется со значением столбца. Таким образом, 0 приведет к 1.

Вы также могли бы использовать TYPEOF функцию, например

 COL3 INTEGER CHECK(typeof(COL3) = 'INTEGER')
  
  • Отмечая, что существует тонкая разница между использованием ПРИВЕДЕНИЯ и TYPEOF. Предыдущие примеры, использующие ПРИВЕДЕНИЕ, допускают использование целых чисел в виде строк, в то время как использование функции typeof допускает только целые числа.

Ниже приведены некоторые примеры ВСТАВОК с результатом :-

 INSERT INTO testinsert VALUES(100,100); -- OK
INSERT INTO testinsert VALUES('100',100); -- OK
INSERT INTO testinsert VALUES('100','abc'); -- ouch for COL2 (abc)
INSERT INTO testinsert VALUES(0,100); -- OK
INSERT INTO testinsert VALUES('0',100); -- OK
INSERT INTO testinsert VALUES('abc',100); -- ouch  for COL1 (abc)
  

С добавлением COL3 в таблицу :-

 INSERT INTO testinsert VALUES(100,100,100); -- OK (all integers)
INSERT INTO testinsert VALUES('100','100',100); -- OK (CAST can accept integers as strings)
INSERT INTO testinsert VALUES('100','100','100'); -- Ouch typeof will consider '100' as a string, not an integer
  

Если вы хотите игнорировать, а не прерывать (по умолчанию), вы могли бы использовать :-

 INSERT OR IGNORE INTO testinsert VALUES('100','abc'); -- insert Skipped - no fail
  

Для тестирования вышеуказанного использовался SQLite Manager.

Вот пример сбоя КОНФЛИКТА :-

 SQLiteManager:  -- OK
INSERT INTO testinsert VALUES('100','abc'); [ CHECK constraint failed: testinsert ]
Exception Name: NS_ERROR_STORAGE_CONSTRAINT
Exception Message: Component returned failure code: 0x80630003 (NS_ERROR_STORAGE_CONSTRAINT) [mozIStorageStatement.execute]
  

Возможно, вы захотите взглянуть на :-

Ответ №3:

Начиная с версии 3.37.0 SQLite, можно принудительно проверять типы данных с помощью СТРОГИХ таблиц:

В инструкции CREATE TABLE, если ключевое слово «STRICT» table-option добавляется в конец после закрывающего «)», то к этой таблице применяются строгие правила ввода.

Вы можете использовать один из следующих типов данных для определений столбцов:

  • INT
  • ЦЕЛОЕ число
  • реальный
  • ТЕКСТ
  • Большой двоичный объект
  • Любой

Смотрите упрощенную демонстрацию.