Как переименовать столбец в таблице базы данных SQLite?

296

Мне нужно было бы переименовать несколько столбцов в некоторых таблицах в базе данных SQLite. Я знаю, что подобный вопрос был задан ранее для stackoverflow, но он был для SQL в целом, и случай SQLite не упоминался.

Из документации SQLite для ALTER TABLE я понял, что невозможно сделать такую ​​вещь "легко" (то есть, с помощью одного оператора ALTER TABLE).

Мне было интересно, кто-то знал об общем способе SQL сделать такое с SQLite.

Джос
источник
Вы можете сделать это, используя db browser для sqlite довольно легко
Matt G
1
Пожалуйста, пометьте этот ответ как принятый stackoverflow.com/a/52346199/124486
Эван Кэрролл

Ответы:

66

Это было исправлено в 2018-09-15 (3.25.0)

Улучшения ALTER TABLEкоманды:

  • Добавлена ​​поддержка переименования столбцов в таблице с помощью ALTER TABLEтаблицы RENAME COLUMN oldname TO newname.
  • Исправьте функцию переименования таблицы, чтобы она также обновляла ссылки на переименованную таблицу в триггерах и представлениях.

Вы можете найти новый синтаксис, документированный в ALTER TABLE

RENAME COLUMN TOСинтаксис меняет имя-столбца таблицы имя-таблицы в новой-имя столбца. Имя столбца изменяется как внутри самого определения таблицы, так и во всех индексах, триггерах и представлениях, которые ссылаются на столбец. Если изменение имени столбца приведет к семантической неоднозначности в триггере или представлении, то происходит RENAME COLUMNсбой с ошибкой, и изменения не применяются.

введите описание изображения здесь Источник изображения: https://www.sqlite.org/images/syntax/alter-table-stmt.gif

Пример:

CREATE TABLE tab AS SELECT 1 AS c;

SELECT * FROM tab;

ALTER TABLE tab RENAME COLUMN c to c_new;

SELECT * FROM tab;

Демоверсия db-fiddle.com


Поддержка Android

На момент написания, Android 27 API использует пакет SQLite версии 3.19 .

Исходя из текущей версии, которую использует Android, и того, что это обновление будет выпущено в версии 3.25.0 SQLite, я бы сказал, что вам нужно немного подождать (примерно API 33), прежде чем поддержка этого будет добавлена ​​в Android.

И даже в этом случае, если вам нужно поддерживать какие-либо версии, более старые, чем API 33, вы не сможете использовать это.

Лукаш Шозда
источник
8
Я реализую миграцию на Android и, к сожалению, IntelliJ показывает предупреждение, что это недопустимая команда SQL. database.execSQL("ALTER TABLE content RENAME COLUMN archiveCount TO dismissCount"), COLUM выделен красным и говорит, что ожидаемый, получил «COLUMN» . К сожалению, Android все еще работает на SQLite версии 3.19, поэтому у меня это не работает.
Адам Гурвиц
1
отредактировано: я обнаружил на system.data.sqlite.org/index.html/doc/trunk/www/faq.wiki#q1 , что 1.0.109.x) фактически использует SQLite 3.24 и System.Data.SQLite использование SQLite 3.25 планируется в этом месяце.
rychlmoj
1
К вашему сведению, к сожалению, это еще не реализовано библиотекой SQLite для Android . Надеюсь, они скоро обновятся.
Адам Гурвиц
3
Я добавил раздел для поддержки Android, чтобы другие не оправдали надежд. Исходя из текущего использования Android 27 SQLite 3.19, нам придется подождать примерно до API 33, прежде чем эта функция будет добавлена ​​в Android, и даже тогда она будет поддерживаться только в последних версиях. Вздох.
Джошуа Пинтер
1
@JoshuaPinter Спасибо за расширение моего ответа.
Лукаш Шозда
448

Допустим, у вас есть таблица, и вам нужно переименовать «colb» в «col_b»:

Сначала вы переименовываете старую таблицу:

ALTER TABLE orig_table_name RENAME TO tmp_table_name;

Затем создайте новую таблицу на основе старой таблицы, но с обновленным именем столбца:

CREATE TABLE orig_table_name (
  col_a INT
, col_b INT
);

Затем скопируйте содержимое напротив исходной таблицы.

INSERT INTO orig_table_name(col_a, col_b)
SELECT col_a, colb
FROM tmp_table_name;

Наконец, бросьте старый стол.

DROP TABLE tmp_table_name;

Заворачивать все это в BEGIN TRANSACTION;и COMMIT;тоже, наверное, хорошая идея.

Evan
источник
51
И не забывайте свои показатели.
Том Мэйфилд
11
Очень важно, что в приведенном выше примере кода отсутствует транзакция. Вы должны завернуть все это в BEGIN / END (или ROLLBACK), чтобы убедиться, что переименование завершено успешно или не завершено вообще.
Роджер Биннс
4
Любой желающий сделать это в Android может реализовать транзакции с использованием SQLiteDatabase.beginTransaction ()
bmaupin
7
В ответе нет кода, который копирует индексы. Создание пустой таблицы и помещение в нее данных только копирует структуру и данные. Если вам нужны метаданные (индексы, внешние ключи, ограничения и т. Д.), Вы также должны выполнить операторы, чтобы создать их на замененной таблице.
Том Мэйфилд
17
.schemaКоманда SQLite удобна для показа CREATE TABLEоператора, который составляет существующую таблицу. Вы можете взять его выходные данные, изменить по мере необходимости и выполнить его для создания новой таблицы. Эта команда также показывает необходимые CREATE INDEXкоманды для создания индексов, которые должны охватывать проблемы Томаса. Конечно, обязательно запустите эту команду, прежде чем что-либо менять.
Майк ДеСимоне
56

Покопавшись, я нашел этот мультиплатформенный (Linux | Mac | Windows) графический инструмент под названием DB Browser for SQLite, который на самом деле позволяет переименовывать столбцы очень удобным для пользователя способом!

Редактировать | Изменить таблицу | Выберите таблицу | Редактировать поле. Нажмите, нажмите! Вуаля!

Однако, если кто-то хочет поделиться программным способом сделать это, я был бы рад узнать!

Джос
источник
1
Существует также дополнение Firefox, которое делает то же самое : щелкните правой кнопкой мыши столбец, который вы хотите переименовать, и выберите «Редактировать столбец».
Джейкоб Хакер
1
Даже в openSUSE он доступен в виде пакета: software.opensuse.org/package/sqlitebrowser
Странно, у него так много голосов. Мы говорим о программировании здесь (код). Почему вы даже опубликовали этот ответ здесь?
user25
2
Там нет упоминания о том, как сделать это с кодом в моем вопросе. Я просто хотел знать, как переименовать столбец в БД SQLite.
19
@ Джо, я люблю тебя !!! (как брат) получил меня изменил поле, вуаля. Я экспортировал таблицу MS Access в SQLite, и в одном из полей перед ним была цифра: 3YearLetterSent. Visual Studio сделала класс из таблицы, но задохнулась от цифры «3» в начале имени поля. Я знаю это, просто не смотрел.
JustJohn
53

Хотя верно то, что ALTER COLUMN отсутствует, если вы хотите переименовать только столбец, удалить ограничение NOT NULL или изменить тип данных, вы можете использовать следующий набор команд:

Примечание. Эти команды могут повредить вашу базу данных, поэтому убедитесь, что у вас есть резервная копия

PRAGMA writable_schema = 1;
UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';
PRAGMA writable_schema = 0;

Вам нужно будет либо закрыть и снова открыть свое соединение, либо очистить базу данных, чтобы перезагрузить изменения в схему.

Например:

Y:\> sqlite3 booktest  
SQLite version 3.7.4  
Enter ".help" for instructions  
Enter SQL statements terminated with a ";"  
sqlite> create table BOOKS ( title TEXT NOT NULL, publication_date TEXT NOT NULL);  
sqlite> insert into BOOKS VALUES ("NULLTEST",null);  
Error: BOOKS.publication_date may not be NULL  
sqlite> PRAGMA writable_schema = 1; 
sqlite> UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';  
sqlite> PRAGMA writable_schema = 0;  
sqlite> .q  

Y:\> sqlite3 booktest  
SQLite version 3.7.4  
Enter ".help" for instructions  
Enter SQL statements terminated with a ";"  
sqlite> insert into BOOKS VALUES ("NULLTEST",null);  
sqlite> .q  

Ссылки следуют:


pragma writable_schema
Когда эта прагма включена, таблицы SQLITE_MASTER, в которых база данных может быть изменена с помощью обычных операторов UPDATE, INSERT и DELETE. Предупреждение: неправильное использование этой прагмы может легко привести к повреждению файла базы данных.

Таблица изменения
SQLite поддерживает ограниченное подмножество ALTER TABLE. Команда ALTER TABLE в SQLite позволяет пользователю переименовать таблицу или добавить новый столбец в существующую таблицу. Невозможно переименовать столбец, удалить столбец или добавить или удалить ограничения из таблицы.

ALTER TABLE SYNTAX

Ной
источник
3
Опасный, но все же, наверное, самый прямой ответ ИМО.
Tek
2
Да, очень быстро - Опасный означает только «Сначала убедитесь, что у вас есть резервная копия»
Ной,
6
Формат файла sqlite очень прост, и поэтому эта операция действительна. Формат файла содержит только два набора информации о таблице: фактическая команда CREATE TABLE в виде простого текста и строки, значения которых отображаются в порядке полей из команды CREATE. Это означает, что код sqlite открывает базу данных, он анализирует каждую команду CREATE и динамически создает информацию о столбцах в памяти. Таким образом, любая команда, которая изменяет команду CREATE таким образом, что заканчивается одинаковым количеством столбцов, будет работать, даже если вы измените их тип или ограничения.
Томас Темпельманн
3
@ThomasTempelmann Однако добавление ограничений, которые не выполняются набором данных, приведет к проблемам, поскольку планировщик запросов предполагает, что ограничения выполнены.
fuz
2
@ThomasTempelmann Удаление ограничений всегда хорошо. Добавление ограничений - это нормально, если ограничение выполняется всеми строками, но вам, безусловно, нужно проверить.
fuz
18

Недавно мне пришлось сделать это в SQLite3 с таблицей с именем points с столбцами id, lon, lat . Ошибочно, когда таблица была импортирована, значения широты хранятся в столбце lon и наоборот, поэтому очевидным решением будет переименование этих столбцов. Итак, фокус был:

create table points_tmp as select id, lon as lat, lat as lon from points;
drop table points;
alter table points_tmp rename to points;

Я надеюсь, что это будет полезно для вас!

aizquier
источник
Этот метод не копирует значение PK надлежащим образом и автоматически создает скрытый столбец rowid. Не обязательно проблема, но хотел указать на это, потому что это стало проблемой для меня.
TPoschel
4
Разве не было бы проще сделать «ОБНОВЛЕНИЕ точек: SET lon = lat, lat = lon;»?
kstep
1
Этот ответ делает процесс в правильном порядке. Сначала создайте временную таблицу и заполните ее, а затем уничтожьте оригинал .
Xeoncross
14

Цитирование документации sqlite :

SQLite поддерживает ограниченное подмножество ALTER TABLE. Команда ALTER TABLE в SQLite позволяет пользователю переименовать таблицу или добавить новый столбец в существующую таблицу. Невозможно переименовать столбец, удалить столбец или добавить или удалить ограничения из таблицы.

Конечно, вы можете создать новую таблицу с новым макетом SELECT * FROM old_tableи заполнить новую таблицу значениями, которые вы получите.

Элазар Лейбович
источник
7

Во-первых, это одна из тех вещей, которая удивляет меня: переименование столбца требует создания совершенно новой таблицы и копирования данных из старой таблицы в новую таблицу ...

GUI, к которому я подключился для выполнения операций SQLite, - это Base . У него есть отличное окно журнала, которое показывает все команды, которые были выполнены. Выполнение переименования столбца через Base заполняет окно журнала необходимыми командами:

Базовое окно журнала

Затем их можно легко скопировать и вставить там, где они могут вам понадобиться. Для меня это в файле миграции ActiveAndroid . Приятно также то, что скопированные данные содержат только команды SQLite, а не временные метки и т. Д.

Надеюсь, это экономит время некоторых людей.

Джошуа Пинтер
источник
FYI, если вы будете с помощью ActiveAndroid , вы можете опустить BEGIN TRANSACTION;и COMMIT;линии, а ActiveAndroid ручки , что сам по себе.
Джошуа Пинтер
6

СЛУЧАЙ 1: SQLite 3.25.0+

Только версия 3.25.0 SQLite поддерживает переименование столбцов. Если ваше устройство отвечает этому требованию, все довольно просто. Следующий запрос решит вашу проблему:

ALTER TABLE "MyTable" RENAME COLUMN "OldColumn" TO "NewColumn";

СЛУЧАЙ 2: Старые версии SQLite

Вы должны следовать другому подходу, чтобы получить результат, который может быть немного хитрым

Например, если у вас есть такая таблица:

CREATE TABLE student(Name TEXT, Department TEXT, Location TEXT)

И если вы хотите изменить название столбца Location

Шаг 1: переименуйте исходную таблицу:

ALTER TABLE student RENAME TO student_temp;

Шаг 2: Теперь создайте новую таблицу studentс правильным именем столбца:

CREATE TABLE student(Name TEXT, Department TEXT, Address TEXT)

Шаг 3: Скопируйте данные из исходной таблицы в новую таблицу:

INSERT INTO student(Name, Department, Address) SELECT Name, Department, Location FROM student_temp;

Примечание. Приведенная выше команда должна состоять из одной строки.

Шаг 4: отбросьте оригинальную таблицу:

DROP TABLE student_temp;

С помощью этих четырех шагов вы можете вручную изменить любую таблицу SQLite. Имейте в виду, что вам также нужно будет заново создать любые индексы, средства просмотра или триггеры для новой таблицы.

Фебин Мэтью
источник
1
Как обновить версию базы данных sqllite до 3.29.0 в Android Studio, я использую API-уровень 28.
Nathani Software
Версия SQLite определяется устройством, на котором работает приложение. Это зависит от устройства.
Февин Мэтью
1
Для людей, использующих старый sqlite, четыре шага выше не рекомендуется. Смотрите раздел «Осторожно» на sqlite.org/lang_altertable.html .
Джефф
3

изменить столбец таблицы <id> на <_id>

 String LastId = "id";

    database.execSQL("ALTER TABLE " + PhraseContract.TABLE_NAME + " RENAME TO " + PhraseContract.TABLE_NAME + "old");
    database.execSQL("CREATE TABLE " + PhraseContract.TABLE_NAME
    +"("
            + PhraseContract.COLUMN_ID + " INTEGER PRIMARY KEY,"
            + PhraseContract.COLUMN_PHRASE + " text ,"
            + PhraseContract.COLUMN_ORDER  + " text ,"
            + PhraseContract.COLUMN_FROM_A_LANG + " text"
    +")"
    );
    database.execSQL("INSERT INTO " +
            PhraseContract.TABLE_NAME + "("+ PhraseContract.COLUMN_ID +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +")" +
            " SELECT " + LastId +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +
            " FROM " + PhraseContract.TABLE_NAME + "old");
    database.execSQL("DROP TABLE " + PhraseContract.TABLE_NAME + "old");
Ваге Гарибян
источник
3

Создайте новый столбец с нужным именем столбца: COLNew.

ALTER TABLE {tableName} ADD COLUMN COLNew {type};

Скопируйте содержимое старого столбца COLOld в новый столбец COLNew.

INSERT INTO {tableName} (COLNew) SELECT {COLOld} FROM {tableName}

Примечание: скобки необходимы в строке выше.

Энтони Эберт
источник
2

Как упоминалось ранее, есть инструмент SQLite Database Browser, который делает это. К счастью, этот инструмент ведет журнал всех операций, выполненных пользователем или приложением. Сделав это один раз и просмотрев журнал приложения, вы увидите соответствующий код. Скопируйте запрос и вставьте по мере необходимости. Работал на меня. Надеюсь это поможет

Крис Литридис
источник
2

Из официальной документации

При некоторых изменениях можно использовать более простую и быструю процедуру, которая никак не влияет на содержимое на диске. Следующая более простая процедура подходит для удаления ограничений CHECK или FOREIGN KEY или NOT NULL, переименования столбцов или добавления, удаления или изменения значений по умолчанию для столбца.

  1. Начать транзакцию.

  2. Запустите PRAGMA schema_version, чтобы определить номер текущей версии схемы. Этот номер понадобится для шага 6 ниже.

  3. Активируйте редактирование схемы, используя PRAGMA writable_schema = ON.

  4. Запустите оператор UPDATE, чтобы изменить определение таблицы X в таблице sqlite_master: UPDATE sqlite_master SET sql = ... WHERE type = 'table' AND name = 'X';

    Предостережение. Внесение изменений в таблицу sqlite_master, как это, сделает базу данных поврежденной и нечитаемой, если изменение содержит синтаксическую ошибку. Рекомендуется провести тщательное тестирование оператора UPDATE в отдельной пустой базе данных, прежде чем использовать его в базе данных, содержащей важные данные.

  5. Если изменение таблицы X также влияет на другие таблицы или индексы, или триггеры являются представлениями в схеме, запустите операторы UPDATE, чтобы изменить эти индексы и представления этих других таблиц. Например, если имя столбца изменяется, все ограничения, триггеры, индексы и представления FOREIGN KEY, которые ссылаются на этот столбец, должны быть изменены.

    Внимание: еще раз внесение изменений в таблицу sqlite_master, как это сделает базу данных поврежденной и нечитаемой, если изменение содержит ошибку. Тщательно протестируйте всю эту процедуру в отдельной тестовой базе данных, прежде чем использовать ее в базе данных, содержащей важные данные, и / или сделайте резервные копии важных баз данных, прежде чем выполнять эту процедуру.

  6. Увеличьте номер версии схемы с помощью PRAGMA schema_version = X, где X на единицу больше номера версии старой схемы, найденного на шаге 2 выше.

  7. Отключите редактирование схемы, используя PRAGMA writable_schema = OFF.

  8. (Необязательно) Запустите PRAGMA unity_check, чтобы убедиться, что изменения схемы не повредили базу данных.

  9. Подтвердите транзакцию, начатую на шаге 1 выше.

Мохаммед Яхья
источник
PRAGMA unity_check не обнаруживает никаких ошибок со схемой.
Graymatter
и в чем проблема с этим?
Мухаммед Яхья
1

Один из вариантов, если вам нужно сделать это в крайнем случае, и если ваш исходный столбец был создан по умолчанию, - это создать новый столбец, который вы хотите, скопировать содержимое в него и в основном «отказаться» от старого столбца (он остается присутствует, но вы просто не используете / не обновляете его и т. д.)

например:

alter table TABLE_NAME ADD COLUMN new_column_name TYPE NOT NULL DEFAULT '';
update TABLE_NAME set new_column_name = old_column_name;
update TABLE_NAME set old_column_name = ''; -- abandon old column, basically

Это оставляет столбец (и если он был создан с NOT NULL, но без значения по умолчанию, то будущие вставки, которые игнорируют его, могут потерпеть неудачу), но если это просто одноразовая таблица, компромиссы могут быть приемлемыми. В противном случае используйте один из других упомянутых здесь ответов или другую базу данных, которая позволяет переименовывать столбцы.

rogerdpack
источник
-3

sqlite3 yourdb .dump> /tmp/db.txt
edit /tmp/db.txt изменить имя столбца в строке «Создать»
sqlite2 yourdb2 </tmp/db.txt
mv / move yourdb2 yourdb

H Bosch
источник
3
ваш ответ не предоставляет никакой информации, куча кода / инструкций выплевывается без какой-либо дополнительной информации о том, почему вы думаете, что это будет работать или что произойдет, если вы запустите его
RGLSV