![]() |
|
|||
WebMoney: WMZ Z294115950220 WMR R409981405661 WME E134003968233 |
Visa 4274 3200 2453 6495 |
Язык SQL это "стандарт". Несмотря на это, никакие два движка
базы данных SQL не работают точно одинаково. У каждого внедрения SQL есть он
собственные особенности и причуды, и SQLite не исключение
из этого правила. Этот документ стремится подчеркнуть основные различия между SQLite и
другими внедрениями SQL как помощь разработчикам, которые портируют
к или от SQLite или кто пытается построить систему, которая работает
через многие ядра базы данных. Если вы пользователь SQLite, который споткнулся о некоторую причуду
SQLite, которая не упоминается здесь, пожалуйста, сообщите разработчикам,
повесив краткое объявление на
SQLite Forum. Сравнивая SQLite с другими системами базы данных SQL, такими как SQL
Server, PostgreSQL, MySQL или Oracle, важно, в первую очередь, понять, что
SQLite не предназначается как замена или конкурент ни одной из тех систем.
SQLite бессерверный. Нет никакого отдельного
серверного процесса, который управляет базой данных.
Приложение взаимодействует с ядром базы данных, используя вызовы функции,
не посылая сообщения в отдельный процесс или поток. То, что SQLite встраиваемый и бессерверный
вместо того, чтобы быть клиент-сервер, является особенностью, не ошибкой. Базы данных клиент-сервер, такие как MySQL, PostgreSQL, SQL Server, Oracle
и другие это важный компонент современных систем. Эти системы решают важную
проблему. Но SQLite решает другую проблему. У SQLite и баз данных
клиент-сервер есть их роль. Разработчики, которые сравнивают SQLite с другими
системами базы данных SQL, должны ясно понять это различие. См. подробности здесь. SQLite гибок относительно типов данных.
Типы данных консультативные, а не обязательные. Некоторые комментаторы говорят, что SQLite "со слабым контролем
типов" и что другие базы данных SQL "со строгим контролем
типов". Мы полагаем, что эти условия неточны.
Мы предпочитаем говорить, что SQLite "гибко типизировано"
и что другие базы данных SQL типизированы строго. См. здесь подробности. Ключевой пункт то, что SQLite очень прощающий относительно типа данных,
которые вы помещаете в базу данных. Например, если у колонки будет тип данных
"INTEGER", и применение вставляет текстовую строку в ту колонку,
SQLite сначала попытается преобразовать текстовую строку в целое число, точно
так же, как любой движок базы данных SQL. Таким образом, если вы вставляете
'1234' в колонку INTEGER, значение преобразована в целое число 1234 и
сохранена. Но, если вы вставляете нечисловую последовательность как
'wxyz' в колонку INTEGER, в отличие от других баз данных SQL, SQLite
не бросает ошибку. Вместо этого SQLite хранит фактическое
значение последовательности в колонке. Точно так же SQLite позволяет вам хранить 2000-символьную строку в колонке
VARCHAR(50). Другие внедрения SQL бросили бы ошибку или усекли бы
последовательность. SQLite хранит все 2000 символов
строки без потери информации и без жалобы. Это заканчивается тем, что вызвало проблемы, когда разработчики делают
некоторую начальную работу, используя SQLite и получают их прикладную работу,
но затем пытаются преобразовать в другую базу данных как PostgreSQL или SQL
Server для развертывания.
Если применение первоначально использует в своих интересах гибкую
типизацию SQLITE, то это потерпит неудачу, когда перемещено в другую базу
данных, которая использует более строгую
политику принудительного присвоения типов. Это особенность SQLite, не ошибка.
Тем не менее, мы признаем, что эта особенность действительно иногда вызывает
беспорядок для разработчиков, которые приучены к работе с другими базами
данных, которые более строги относительно правил типа данных. Ретроспективно,
возможно это было бы менее запутывающим, если бы SQLite просто осуществил тип
данных ANY так, чтобы разработчики могли явно заявить, когда они хотели
использовать гибкую типизацию вместо того, чтобы делать гибкую типизацию
по умолчанию. Поэтому SQLite version 3.37.0 (2021-11-27) ввел опцию
таблицы STRICT.
Они налагают обязательные ограничения типа данных, найденные в других
системах базы данных SQL, или позволяют явному типу данных ANY сохранять
гибкую типизацию SQLite. В отличие от большинства других внедрений SQL, у SQLite нет отдельного
булева типа данных. Вместо этого TRUE и FALSE
(обычно) представляются как целые числа 1 и 0, соответственно.
Это, кажется, не вызывает много проблем, поскольку мы редко получаем жалобы
на это. Но важно признать. С SQLite version 3.23.0
(2018-04-02) SQLite также понимает ключевые слова TRUE и FALSE
псевдонимами для целочисленных значений 1 и 0, соответственно.
Это предоставляет лучшую совместимость с другими внедрениями SQL.
Но для совместимости, если есть колонки под названием TRUE или FALSE,
ключевые слова рассматривают как идентификаторы, ссылающиеся на те
колонки, а не литералы BOOLEAN. У SQLite нет типа данных DATETIME.
Вместо этого даты и время могут быть сохранены любым из этих способов: Встроенные функции даты и времени SQLite
понимают дату/время во всех форматах выше и могут свободно
измениться между ними. Поскольку SQLite гибкий и прощающий относительно типов данных,
могут быть созданы столбцы таблицы, у которых нет указанного типа данных
вообще. Например так: У таблицы "t1" есть четыре колонки "a", "b",
"c" и "d", у которых нет конкретного назначенного типа
данных. Можно сохранить что-либо, что вы хотите, в любой из тех колонок. SQLite разобрал ограничения внешнего ключа
с незапамятных времен, но добавил способность на самом деле провести в жизнь
те ограничения намного позже с
version 3.6.19 (2009-10-14).
К тому времени, когда ограничительное осуществление внешнего ключа было
добавлено, уже были бесчисленные миллионы баз данных в обращении, которое
содержало ограничения внешнего ключа, некоторые из которых не были правильны.
Чтобы избежать ломать те унаследованные базы данных, ограничительное
осуществление внешнего ключа выключено по умолчанию в SQLite. Приложения могут активировать осуществление внешнего ключа во время
выполнения, используя
PRAGMA foreign_keys. Или осуществление внешнего ключа может быть
активировано во время компиляции, используя
-DSQLITE_DEFAULT_FOREIGN_KEYS=1. Обычно (исключения: таблицы
INTEGER PRIMARY KEY и
WITHOUT ROWID) PRIMARY KEY
в таблице SQLite действительно то же самое, как ограничение UNIQUE.
Из-за исторического надзора, значениям столбцов такого PRIMARY KEY
позволяют быть NULL. Это ошибка, но к тому времени, когда проблема была
обнаружена, было столько баз данных в обращении, которые зависели от ошибки,
что решение было принято, чтобы поддержать именно такое поведение. Значение столбца INTEGER PRIMARY KEY
должно всегда быть целым числом не-NULL. Колонки PRIMARY KEY таблиц
WITHOUT ROWID
также должны быть не NULL. В большинстве внедрений SQL колонки вывода
агрегатного запроса могут сослаться только на агрегатные функции или колонки,
названные в пункте GROUP BY. Это не проявляет здравый смысл сослаться на
обычную колонку в агрегатном запросе, потому что каждая строка вывода
могла бы быть составлена из двух или больше строк
во входной таблице (таблицах). SQLite не проводит в жизнь это ограничение. Колонки вывода агрегатного
запроса могут быть произвольными выражениями, которые включают колонки, не
найденные в пункте GROUP BY. У этой особенности есть два использования: С SQLite (но не любое другое внедрение SQL, о котором мы знаем),
если агрегатный запрос содержит единственную функцию min() или max(),
значения колонок, используемых в выводе, взяты от строки, где было достигнуто
значение min() или max(). Если у двух или больше строк
будет то же самое значение min() или max(),
то значения колонок будут выбраны произвольно из одной из тех строк. Например, найти самого высокооплачиваемого сотрудника: В запросе выше значения для колонок first_name и
last_name будут соответствовать строке, которая удовлетворила условие
max(salary). Если запрос не содержит агрегатных функций вообще, то пункт GROUP BY
может быть добавлен вместо DISTINCT ON. Другими словами, строки вывода
фильтрованы так, чтобы только одну строку показали для каждого отличного
набора значений в пункте GROUP BY. Если у двух или больше строк вывода
иначе был бы тот же самый набор значений для колонок GROUP BY, то одна из
строк выбрана произвольно. SQLite поддерживает DISTINCT, но не DISTINCT ON,
функциональность которого обеспечивается вместо этого GROUP BY. SQLite не знает о различии верхнего регистра/нижнего регистра для всех
знаков unicode. Функции SQL upper() и lower()
работают только со знаками ASCII. Есть две причины этого: Полное сворачивание unicode поддерживается в SQLite, если это собрано с
-DSQLITE_ENABLE_ICU и связано с
библиотекой International Components
for Unicode.
Стандарт SQL требует двойных кавычек вокруг идентификаторов и одинарных
кавычек вокруг строковых литералов. Например: SQLite принимает оба из вышеупомянутых. Но, чтобы быть совместимым с MySQL
3.x (который был одним из наиболее широко используемых RDBMS,
когда SQLite сначала разрабатывался), SQLite будет также интерпретировать
последовательность двойных кавычек как строковый литерал, если это не будет
соответствовать никакому действительному идентификатору. Это означает, что идентификатор в двойных кавычках с орфографической
ошибкой будет интерпретироваться как строковый литерал, вместо того, чтобы
произвести ошибку. Это также соблазняет разработчиков, которые плохо знакомы
с языком SQL в дурную привычку к использованию
строковых литералов, когда они действительно должны учиться использовать
правильную форму строкового литерала. В ретроспективе, мы не должны были пытаться заставить SQLite принять
синтаксис MySQL 3.x и никогда не должны были позволять
строковые литералы в двойных кавычках. Однако, есть бесчисленные запросы,
которые используютстроковые литералы и таким образом, мы продолжаем
поддерживать ту способность, чтобы избежать ломать наследие. С SQLite 3.27.0 (2019-02-07) использование строкового литерала
в двойных кавычках заставляет предупреждающее сообщение быть посланным в
журнал ошибок. С SQLite 3.29.0 (2019-07-10) использование
строковых литералов в двойных кавычках
может быть отключено во время выполнения, используя
SQLITE_DBCONFIG_DQS_DDL и
SQLITE_DBCONFIG_DQS_DML в
to sqlite3_db_config().
Настройки по умолчанию могут быть изменены во время компиляции, используя
-DSQLITE_DQS=N.
Разработчики приложений поощряются собирать с использованием
-DSQLITE_DQS=0, чтобы отключить строковый литерал в двойных кавычках
по умолчанию. Если это невозможно, то отключите их
для отдельных соединений с базой данных, используя C-код: Или, если они отключены по умолчанию, но должны быть выборочно позволены
для некоторых исторических соединений с базой данных, которые могут быть
сделаны, используя тот же самый C-код, как показано выше,
с третьим параметром, измененным от 0 до 1. С SQLite 3.41.0 (2023-02-21) SQLITE_DBCONFIG_DQS_DDL и
SQLTIE_DBCONFIG_DQS_DML отключены по умолчанию в
CLI. Используйте ".dbconfig", чтобы повторно
позволить устаревшее поведение при желании. Язык SQL богат ключевыми словами. Большинство внедрений SQL не позволяет
ключевым словам использоваться в качестве идентификаторов (названия таблиц
или колонок), если они не в двойных кавычках.
Но SQLite более гибок. Много ключевых слов могут использоваться в качестве
идентификаторов, не будучи цитированными, пока те ключевые слова используются
в контексте, где ясно, что они предназначаются,
чтобы быть идентификатором. Например, следующее действительно в SQLite: Тот же самый SQL-оператор потерпит неудачу на любом внедрении SQL,
о котором мы знаем из-за использования ключевых слов "union", "true" и
"with" как идентификаторы. Способность использовать ключевые слова в качестве идентификаторов
способствует совместимости. Поскольку новые ключевые слова добавляются,
устаревшие схемы, которые просто, оказывается, используют те ключевые слова в
качестве имен, продолжают работать. Однако, способность использовать ключевое
слово в качестве идентификатора иногда приводит к
удивительным результатам. Например: Триггер, созданный предыдущим запросом, называют "AFTER", и это триггер
типа "BEFORE". "AFTER" используется в качестве идентификатора вместо
ключевого слова, поскольку это единственный способ разобрать запрос.
Другой пример: Таблица tableZ имеет отдельный столбец под названием "INTEGER".
У той колонки нет определенного типа данных, но это PRIMARY KEY. Колонка
не INTEGER PRIMARY KEY
для таблицы, потому что у этого нет типа данных. Символ "INTEGER"
используется в качестве идентификатора для имени столбца, а не как ключевое
слово типа данных. Оригинальное внедрение SQLite стремилось следовать
Postel's Law
, в котором говорится частично "Быть либеральным в том, что вы
принимаете". Это раньше считалось хорошим дизайном,
что система примет изворотливые входы и попытается сделать лучшее, что можно,
не жалуясь слишком много. Но в последнее время, люди сообразили, что иногда
лучше быть строгим в том, что вы принимаете, чтобы более легко найти
ошибки во входе. AUTOINCREMENT в SQLite
действует по-другому, чем в MySQL. Это часто вызывает беспорядок для людей,
которые первоначально изучили SQL на MySQL, затем начали использовать SQLite
и ожидают, что эти две системы будут работать тождественно. См. здесь для подробных инструкций относительно
того, что AUTOINCREMENT делает и не делает в SQLite. NUL-символы (код ASCII 0x00 и Unicode \u0000)
могут появиться посреди последовательностей в SQLite.
Это может привести к неожиданному поведению. Посмотрите подробности
здесь. SQLite говорит, что следующий запрос вернет false: Это потому что целое число не последовательность.
Любой движок базы данных SQL говорит, что это true по причинам, которые
создатель SQLite не понимает.
Choose any three.
1. Обзор
2.
SQLite встраиваемый, не клиент-сервер
3. Гибкие типы
3.1. Нет отдельного типа BOOLEAN
3.2.
Нет отдельного типа DATETIME
3.3.
Тип данных дополнительный
CREATE TABLE t1(a,b,c,d);
4. Осуществление внешнего ключа выключено по умолчанию
5. PRIMARY KEY могут иногда содержать NULL
6. Агрегатные запросы могут содержать несовокупные столбцы
результата, которые не находятся в пункте GROUP BY
SELECT max(salary), first_name, last_name FROM employee;
7. Не делает полной свертки регистра в Unicode по умолчанию
8. Строковые литералы в двойных кавычках приняты
sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 0, (void*)0);
sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 0, (void*)0);
9. Ключевые слова могут часто
использоваться в качестве идентификаторов
CREATE TABLE union(true INT, with BOOLEAN);
CREATE TRIGGER AFTER INSERT ON tableX BEGIN
INSERT INTO tableY(b) VALUES(new.a);
END;
CREATE TABLE tableZ(INTEGER PRIMARY KEY);
10. Сомнительный SQL позволен без любой ошибки или предупреждения
11. AUTOINCREMENT не работает как в MySQL
12. Символы NUL разрешаются в текстовых строках
13. SQLite различает текстовые литералы и Integer
SELECT 1='1';