Существует некоторая путаница и непоследовательность в том, как SQLite и различные реализации Mozilla, Google, Adobe и других обрабатывают числовые первичные ключи в базах данных, таблицы которых были созданы вне этих реализаций, и где первичные ключи были определены как целое число.тип, но не как «INTEGER» [дословно] - то есть они были определены как INT или INT16 или INT32 и т. д.
INTEGER PRIMARY KEY in mothership SQLite is an alias for the rowid.
INT PRIMARY KEY in mothership SQLite is not an alias for the rowid.
Член консорциума (или любой разработчик) может или не может следовать этому правилу,(SQLite находится в свободном доступе, конечно.)
См. Раздел 2.0 здесь: http://www.sqlite.org/datatypes.html
и см. Раздел по RowId и первичному ключу здесь: http://www.sqlite.org/lang_createtable.html#rowid
Столбец PRIMARY KEY становится целочисленным первичным ключом только в том случае, если объявленное имя типа является точно "INTEGER".Другие имена целочисленных типов, такие как «INT», «BIGINT», «SHORT INTEGER» или «UNSIGNED INTEGER», заставляют столбец первичного ключа вести себя как обычный столбец таблицы с целочисленным сходством и уникальным индексом, не как псевдоним дляrowid .[выделение добавлено]
Разработчик, который не следует правилу, возможно, даже не подозревал, что он нарушает правило, так как это правило "запятнанного".В любом случае, это означает, что на практике одна реализация может обрабатывать предоставленное значение как псевдоним для rowid, а другая реализация - нет.Если задано значение 10, можно получить кортеж, у которого rowid = 10, а можно получить кортеж, где значение указанного столбца = 10. Это, конечно, приводит к ложным результатам в запросах, и они могут выглядеть очень хорошо иправдоподобные результаты, но они совершенно неверны.
Рассмотрим следующий простой тест: с использованием основных утилит SQLite, а не предоставляемых одним из разработчиков, выполняются следующие операторы DDL и DML;затем в своей реализации откройте базу данных и снова выполните операторы DML, чтобы сравнить результаты DML:
CREATE TABLE TEST
("id" INT PRIMARY KEY, "name" text) -- ** NOTE "INT" not "INTEGER"
INSERT INTO TEST
(id, name)
VALUES
(7,'seven')
** *** N.B. THE ROWID OF THE ROW INSERTED ABOVE = 1 *** **
select rowid, id, name from test
result: 1 | 7 | seven
select * from TEST
result: 7 | seven
select * from TEST where id = 7
result: ????? [ymmv]
select * from TEST where id = 1
result: ????? [ymmv]
В зависимости от того, как конкретная реализация обрабатывает первичный ключ INT, третий оператор выбора выше (выберите * изTEST, где id = 7) может возвращать одну строку или может ничего не возвращать!
Если реализация рассматривает INT PK как псевдоним для идентификатора строки, ну, нет строки, чьяrowid = 7, и поэтому он ничего не вернет.Если реализация рассматривает INT PK как обычное значение, она найдет строку.
Теперь, если бы вы вставили больше строк в таблицу TEST, вы в конечном итоге создали бы строку, у которой rowid = 7. В одномиз этих своенравных реализаций, когда вы используете это предложение where - , где id = 7 --- вы можете подумать, что обращаетесь к кортежу с id = 7, но на самом деле вы обращаетесь к кортежу, чейROWID = 7.Вы могли бы получить неправильный кортеж и не могли бы этого понять.Рассмотрим возможности при присоединении дочерней таблицы к родительской таблице: дочерняя таблица содержит значение внешнего ключа, равное 7. Какой кортеж возвращает внутреннее соединение из родительской таблицы?Это зависит от того, учитывает ли реализация различие между первичными ключами INT и INTEGER.
В прошлом году я тщательно задокументировал это для Adobe AIR, BTW, а также сообщил об этом в группе новостей SQLite.Возможно, что некоторые реализации за это время изменили поведение.
При создании таблиц SQLite лучше всего использовать INTEGER [дословно] для первичных ключей, а не другие распознаваемые типы int.